7. Animal data (weight, PFOS, SCFA, pH, transit time)
1 INFO
This document contains the commands necessary to analyse experimental data obtained from “Fibrex” (internal project name: B-02-22), not including 16S-based microbiota data.
2 PROJECT
“Fibrex” refers to an animal study with the scope of investigating the effect of dietary fibres on uptake and wash-out of orally administered perfluorooctane sulfonic acid (PFOS) in adult male rats. The setup of the study is described below including a graphical overview of the setup:
48 adult male Sprague-Dawley rats were acclimatised (7 days prior to study start) to, and continuously fed, either:
- Research Diet AIN-93G feed (“feed” LF) with no soluble dietary fibres and mineral caseine (serial number D19090404), or
- Altromin 1314 (“feed” HF), containing dietary fibres.
Half of the rats were dosed with corn oil with or without PFOS daily for 7 days by oral gavage (2 mL / kg):
- 12 rats in each fed group were given pure corn oil as control
(“treatment” CTRL)
- R01-12 for AIN-93G (LF_CTRL)
- R25-36 for Altromin (HF_CTRL)
- 12 rats in each fed group were given corn oil with suspended 1.5
mg/mL PFOS (3 mg / kg) (“treatment” PFOS)
- R13-24 for AIN-93G (LF_PFOS)
- R37-48 for Altromin (HF_PFOS)
- 12 rats in each fed group were given pure corn oil as control
(“treatment” CTRL)
Study period run from Day 0 to Day 21:
Day 0: Feces samples and first transit time was measured
Day 1-7: Dosing period - oral gavage was given daily in the morning (~ 06:00 - 08:00)
- Body weight was measured daily
- Day 7: Second transit time measured
Day 8: Dissection of half of each group
- Body weight, feces and urine samples were collected from all animals in the morning (except urine for R19)
- Blood samples from tongue-vein was taken from all animals not dissected
- Animals dissected:
- R01-06
- R13-18
- R25-30
- R37-40 + R43-44
Day 8-21: Wash-out period - all remaining rats were measured for PFOS in blood, feces and urine
- Day 12: Feces samples and body weight
- Day 16: Feces, urine, tongue-vein blood samples and body weight
- Day 20: Third transit time measured
Day 21: Dissection of remaining 24 rats
- Body weight, feces and urine samples were collected prior to dissection
- Animals dissected:
- R07-12
- R19-24
- R31-37
- R41-42 + R45-48
During each dissections following samples and information were collected:
- Weight: Cecum weight, and Liver weight
- Blood samples
- Tissue samples:
- Liver
- Brain
- Gastrointestinal samples from:
- Upper and lower jejunum
- Ileum
- Cecum
2.1 CONTENT
The project data contains:
Animal identifiers:
- “rat_org” lists rat names as given during the study
- “rat_name” is corrected rat names due to non-continuous numbering for rat_org and dissection days for rat_org R41-R42 (day 21) and R43-R44 (day 8). This column should be used for rat identification - same is corrected in metadata for microbiome data. All following information is following rat_name nomenclature.
- “cage” number (01-24)
- “feed” given during the study: LF = no fibre, and HF = fibre
- “treatment” for oral gavage given: CTRL for control, and PFOS for PFOS
- “dissection” for dissection days of each rat: d8 and d21
- combined identifiers with values from above separated by “_“:”feedtreat”, “feedtreatday”
Animal weight data (grams) including calculated weights per bw (ratio) and normalized weight data (normalised after mean weight of control group):
- Body weight (“bw” followed by number of day) from day 0 to day 8 and subsequent days 12, 16, 20 and 21, including bw gain from day 0 - 8, 0 - 21, and 8 - 21.
- Liver and cecum weight from dissections on day 8 and 21
- Estimated brain weights per rat (“brain_wt_estimate”) based on “Herculano-Houzel, Mota, and Lent - 2006”
- Estimated blood volume per rat (“bloodvol_8”, “bloodvol_16”, “bloodvol_21”) based on an standard average of 64mL blood / kilogram in rats “Diehl et al. 2001”
Transit time per rat in minutes for:
- Day 0 (“transit_0”) - note: measurement were done per cage of 2 rats, hence the real value is not known for individual rats
- Day 7 (“transit_7”)
- Day 20 (“transit_20”)
Total dosed volume (mL) of oral gavage per rat (“dose_total_ml”)
PFOS quantitative data in ug / g (“_ugg”) or ug / mL (“_ugml), or mg total (“_mg”) as well as PFOS isomer data:
- Total dosed PFOS per rat on day 8 (“pfos_total_mg”), respectively
- Systemic samples:
- Liver values for day 8 and 21
- Brain values for day 8 and 21 (except R01, R02, R13, R40, R43, due to missing or loss of sample)
- Blood serum values for day 8, 16, and 21
- Secreted / Wash-out samples:
- Cecum values for day 8 and 21 (except R04)
- Feces values for day 8, 12, 16, and 21
- Urine values for day 8, 16, and 21
pH measurements of gastrointestinal contents by 4x dilution (wt/vol) in sterile nuclease-free water:
- Upper and lower jejunum
- Ileum
- Cecum (except R04)
Short-chain fatty acids quantification of 10 compounds in cecal water from day 8 and 21 given in mM:
- formic acid (formate),
- acetic acid (acetate),
- propanoic acid (propionate),
- 2-methyl-propanoic acid (isobutyrate),
- butanoic acid (butyrate),
- 3-methyl-butanoic acid (isovalerate),
- pentanoic acid (valerate),
- 4-methyl-pentanoic acid (isocaproate, not included due to low sample count > LOD),
- hexanoic acid (coproate) and
- heptanoic acid (enanthate, not included due to low sample count > LOD)
The following content of this document goes through data analysis of the above mentioned data and contains code for creation of figures used for the associated publication.
3 SETUP
Following code loads packages, creates necessary folder and saves parameters for the following analyses.
knitr::opts_chunk$set(echo = TRUE)
# Load libraries
library(tidyverse)
library(phyloseq)
library(decontam)
library(pals)
library(ggpubr)
library(vegan)
library(phangorn)
library(kableExtra)
library(plotly)
library(rstatix)
library(forcats)
library(dplyr)
library(tidyr)
library(ggplot2)
library(cowplot)
library(DAtest)
library(ggrepel)
# Save params
saveRDS(params, file = "R_objects/animal_params.RDS")4 LOAD DATA
Loading data from CSV-format in input folder and saves as Rdata-format.
# Load analysis data
dat <- read.csv(params$input, header = TRUE, sep = ";", dec = ",")
save(dat, file = "R_objects/animal_data.Rdata")
# clear the environment and release memory
rm(list = ls(all.names = TRUE)) #will clear all objects includes hidden objects.
invisible(gc()) #free up memory and report the memory usage.5 ANIMAL WEIGHT DATA
Animal weight data contains data from body weight through the entire study period with calculated body weight gain, and organ weights from cecum and liver.
5.1 Body weight gain - Day 0-8 (n = 48)
This section will prepare to perform the data analysis for body weight gain
5.1.1 Prepare data
This section sets the variables to be used and prepares the data if necessary.
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
dat.clean <- dat
# Set names of variables
PREDICTOR <- "feedtreat"
OUTCOME <- "bw_gain08"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = c("mean_sd"))## # A tibble: 4 × 5
## feedtreat variable n mean sd
## <chr> <fct> <dbl> <dbl> <dbl>
## 1 HF_CTRL bw_gain08 12 21.3 3.46
## 2 HF_PFOS bw_gain08 12 19.4 3.46
## 3 LF_CTRL bw_gain08 12 24.1 3.54
## 4 LF_PFOS bw_gain08 12 23.5 3.08
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = c("full"))## # A tibble: 4 × 14
## feedtreat variable n min max median q1 q3 iqr mad mean
## <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF_CTRL bw_gain08 12 16.9 26.7 20.2 18.6 24.3 5.69 3.43 21.3
## 2 HF_PFOS bw_gain08 12 12.8 24.5 19.6 17.8 21.5 3.7 2.96 19.4
## 3 LF_CTRL bw_gain08 12 18.4 28.7 23.9 21.0 27.2 6.17 4.65 24.1
## 4 LF_PFOS bw_gain08 12 18.7 27.7 23.7 21.7 25.8 4.09 3.55 23.5
## # ℹ 3 more variables: sd <dbl>, se <dbl>, ci <dbl>
# Create plot
bxp <- dat.clean %>%
ggboxplot(x = if_else(length(PREDICTOR) > 1, PREDICTOR[2],PREDICTOR[1]),
y = OUTCOME,
color = PREDICTOR[1],
facet.by = if(length(PREDICTOR) == 3) PREDICTOR[3],
palette = params$COL)
bxp
Assumptions and preliminary tests
The ANOVA tests assume the following characteristics about the data:
Independence of the observations. Each subject should belong to only one group. There is no relationship between the observations in each group.
This is already done for the whole projectNo significant outliers in the two groups
Normality. the data for each group should be approximately normally distributed.
Homogeneity of variances. the variance of the outcome variable should be equal in each group.
In this section, we’ll perform some preliminary tests to check whether these assumptions are met.
Identify outliers
Outliers can be easily identified using boxplot methods, implemented in
the R function identify_outliers() [rstatix package].
# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## [1] feedtreat rat_org rat_name dissection
## [5] cage treatment feed feedtreatday
## [9] bw_minus18 bw_0 bw_1 bw_2
## [13] bw_3 bw_4 bw_5 bw_6
## [17] bw_7 bw_8 bw_12 bw_16
## [21] bw_21 bw_gain08 bw_gain021 bw_gain821
## [25] bloodvol_8 bloodvol_16 bloodvol_21 cecum_wt
## [29] cecum_wtbw cecum_norm liver_wt liver_wtbw
## [33] liver_norm brain_wt_estimate transit_0 transit_7
## [37] transit_20 dose_total_ml pfos_total_mg pfos_liver_ugg
## [41] pfos_liver_mg pfos_liver8_pct pfos_brain_ugg pfos_brain_uggbw
## [45] pfos_brain_ug pfos_brain_pct pfos_serum8_ugml pfos_serum8_mg
## [49] pfos_serum8_pct pfos_serum16_ugml pfos_serum16_mg pfos_serum16_pct
## [53] pfos_serum21_ugml pfos_serum21_mg pfos_serum21_pct pfos_feces8_ugg
## [57] pfos_feces12_ugg pfos_feces16_ugg pfos_feces21_ugg pfos_cecum_ugg
## [61] pfos_urine8_ugml pfos_urine16_ugml pfos_urine21_ugml pH_je_up
## [65] pH_je_down pH_ileum pH_cecum acetic
## [69] formic propanoic m2_propanoic butanoic
## [73] m3_butanoic pentanoic m4_pentanoic hexanoic
## [77] heptanoic is.outlier is.extreme
## <0 rækker> (eller 0-længde row.names)
Data contains two outliers: sample from rat_name R01 and R30.
Check normality
QQ plot and Shapiro-Wilk test of normality are used to analyze the model
residuals.
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.961 0.114
Test homogneity of variance assumption
1. The residuals versus fits plot can be used to check the homogeneity
of variances.
- It’s also possible to use the Levene’s test to check the homogeneity of variances:
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 3 44 0.133 0.940
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
This shows that body weight gain data has two outliers, has equal variance and is normally distributed without the outliers according to Shapiro-Wilk test. Therefore we use a one-way ANOVA test with Tukey’s honest significance test.
5.1.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 feedtreat 3 44 4.863 0.005 * 0.249
Perform posthoc test
A significant one-way ANOVA is generally followed up by Tukey post-hoc tests to perform multiple pairwise comparisons between groups. When running relaxed Welch one-way test, the Games-Howell post hoc test or pairwise t-tests (with no assumption of equal variances) can be used to compare all possible combinations of group differences.
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 6 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 feedtreat HF_CTRL HF_PFOS 0 -1.88 -5.57 1.82 0.533
## 2 feedtreat HF_CTRL LF_CTRL 0 2.84 -0.851 6.54 0.184
## 3 feedtreat HF_CTRL LF_PFOS 0 2.21 -1.49 5.91 0.391
## 4 feedtreat HF_PFOS LF_CTRL 0 4.72 1.03 8.42 0.00737
## 5 feedtreat HF_PFOS LF_PFOS 0 4.09 0.392 7.78 0.025
## 6 feedtreat LF_CTRL LF_PFOS 0 -0.634 -4.33 3.06 0.968
## # ℹ 1 more variable: p.adj.signif <chr>
5.1.3 Create nested figure
# Set variables for inner and outer analysis, and variable for facet
INNER.VAR <- "treatment"
OUTER.VAR <- "feed"
FACETVAR <- "dissection"
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(.data[[OUTER.VAR]]) %>%
t_test(as.formula(paste(OUTCOME,"~",INNER.VAR, sep = " ")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
# adjust_pvalue(method = "bonferroni") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## feed estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 HF 1.88 21.3 19.4 bw_gai… CTRL PFOS 12 12 1.33
## 2 LF 0.634 24.1 23.5 bw_gai… CTRL PFOS 12 12 0.468
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
# group_by(.data[[FACETVAR]]) %>%
t_test(as.formula(paste(OUTCOME,"~", OUTER.VAR, sep = " ")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
# adjust_pvalue(method = "bonferroni") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 -3.47 20.3 23.8 bw_ga… HF LF 24 24 -3.54 9.3e-4
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = OUTER.VAR, dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = OUTER.VAR)
stat.out$y.position <- max(stat.in$y.position)*1.1
# Sort dat.clean
dat.clean <- dat.clean[order(dat.clean$feedtreat),]
# Create plot
p <- ggboxplot(dat.clean, x = OUTER.VAR, y = OUTCOME,
color = PREDICTOR,
fill = PREDICTOR,
add = "jitter",
add.params = list(size = 1)) +
scale_fill_manual(values = params$COL1, name = "Group", labels = c("HF_CTRL" = "HF-CTRL","HF_PFOS" = "HF-PFOS","LF_CTRL" = "LF-CTRL","LF_PFOS" = "LF-PFOS")) +
scale_color_manual(values = c("black","black","black","black")) +
scale_y_continuous(name = "Bodyweight gain",limits = c(10,35),breaks = seq(10,35,5), labels = function(x) paste0(x, "%")) +
guides(color = "none") +
theme(axis.title.x = element_blank())
p <- p + stat_pvalue_manual(stat.in, label = "p.format",tip.length = 0, hide.ns = FALSE)+
stat_pvalue_manual(stat.out, label = "p.format", tip.length = 0, hide.ns = FALSE)
p# Plot for saving without legend
p2 <- p + theme(legend.position = "none")
# Output plot
ggsave(filename = paste0("plots/animal_data/weight/",OUTCOME,"_plot.png"), p2, device = "png", dpi = 300, units = "mm", width = 100, height = 100)
ggsave(filename = paste0("plots/animal_data/weight/",OUTCOME,"_plot.pdf"), p2, device = "pdf", dpi = 300, units = "mm", width = 100, height = 100)
# clear the environment and release memory
rm(list = ls(all.names = TRUE)) #will clear all objects includes hidden objects.
invisible(gc()) #free up memory and report the memory usage.5.2 Body weight gain - Day 0-21 (n = 24)
This section will prepare to perform the data analysis for body weight gain
5.2.1 Prepare data
This section sets the variables to be used and prepares the data if necessary.
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Subset
dat.clean <- subset(dat, !is.na(bw_gain021))
# Set names of variables
PREDICTOR <- "feedtreat"#c("treatment","pfos","van")
OUTCOME <- "bw_gain021"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 4 × 5
## feedtreat variable n mean sd
## <chr> <fct> <dbl> <dbl> <dbl>
## 1 HF_CTRL bw_gain021 6 45.5 6.86
## 2 HF_PFOS bw_gain021 6 47.4 5.93
## 3 LF_CTRL bw_gain021 6 57.0 7.82
## 4 LF_PFOS bw_gain021 6 53.0 5.48
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = c("full"))## # A tibble: 4 × 14
## feedtreat variable n min max median q1 q3 iqr mad mean
## <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF_CTRL bw_gain021 6 36.5 54.6 46.8 40.3 49.3 8.92 7.71 45.5
## 2 HF_PFOS bw_gain021 6 36.6 52.1 49.5 45.7 51.3 5.58 3.67 47.4
## 3 LF_CTRL bw_gain021 6 48.9 68.1 54.3 51.6 62.7 11.1 6.40 57.0
## 4 LF_PFOS bw_gain021 6 47.0 60.8 53.1 48.2 56.2 8.03 7.24 53.0
## # ℹ 3 more variables: sd <dbl>, se <dbl>, ci <dbl>
# Create plot
bxp <- dat.clean %>%
ggboxplot(x = if_else(length(PREDICTOR) > 1, PREDICTOR[2],PREDICTOR[1]),
y = OUTCOME,
color = PREDICTOR[1],
facet.by = if(length(PREDICTOR) == 3) PREDICTOR[3],
palette = params$COL)
bxp# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 1 × 79
## feedtreat rat_org rat_name dissection cage treatment feed feedtreatday
## <chr> <chr> <chr> <chr> <int> <chr> <chr> <chr>
## 1 HF_PFOS R46 R46 d21 23 PFOS HF HF_PFOS_d21
## # ℹ 71 more variables: bw_minus18 <dbl>, bw_0 <dbl>, bw_1 <int>, bw_2 <int>,
## # bw_3 <int>, bw_4 <int>, bw_5 <int>, bw_6 <int>, bw_7 <int>, bw_8 <int>,
## # bw_12 <dbl>, bw_16 <dbl>, bw_21 <dbl>, bw_gain08 <dbl>, bw_gain021 <dbl>,
## # bw_gain821 <dbl>, bloodvol_8 <dbl>, bloodvol_16 <dbl>, bloodvol_21 <dbl>,
## # cecum_wt <dbl>, cecum_wtbw <dbl>, cecum_norm <dbl>, liver_wt <dbl>,
## # liver_wtbw <dbl>, liver_norm <dbl>, brain_wt_estimate <dbl>,
## # transit_0 <int>, transit_7 <int>, transit_20 <int>, dose_total_ml <dbl>, …
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.969 0.636
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 3 20 0.302 0.824
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
This shows that body weight gain data has two outliers, has equal variance and is normally distributed without the outliers according to Shapiro-Wilk test. Therefore we use a one-way ANOVA test with Tukey’s honest significance test.
5.2.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 feedtreat 3 20 3.817 0.026 * 0.364
Perform posthoc test
A significant one-way ANOVA is generally followed up by Tukey post-hoc tests to perform multiple pairwise comparisons between groups. When running relaxed Welch one-way test, the Games-Howell post hoc test or pairwise t-tests (with no assumption of equal variances) can be used to compare all possible combinations of group differences.
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 6 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj p.adj.signif
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 feed… HF_CT… HF_PF… 0 1.86 -8.78 12.5 0.961 ns
## 2 feed… HF_CT… LF_CT… 0 11.5 0.838 22.1 0.0316 *
## 3 feed… HF_CT… LF_PF… 0 7.46 -3.18 18.1 0.235 ns
## 4 feed… HF_PF… LF_CT… 0 9.62 -1.02 20.3 0.0853 ns
## 5 feed… HF_PF… LF_PF… 0 5.61 -5.04 16.2 0.471 ns
## 6 feed… LF_CT… LF_PF… 0 -4.02 -14.7 6.63 0.719 ns
5.2.3 Create nested figure
# Set variables for inner and outer analysis, and variable for facet
INNER.VAR <- "treatment"
OUTER.VAR <- "feed"
FACETVAR <- "dissection"
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(.data[[OUTER.VAR]]) %>%
t_test(as.formula(paste(OUTCOME,"~",INNER.VAR, sep = " ")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
# adjust_pvalue(method = "bonferroni") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## feed estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 HF -1.86 45.5 47.4 bw_gai… CTRL PFOS 6 6 -0.502
## 2 LF 4.02 57.0 53.0 bw_gai… CTRL PFOS 6 6 1.03
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
# group_by(.data[[FACETVAR]]) %>%
t_test(as.formula(paste(OUTCOME,"~", OUTER.VAR, sep = " ")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
# adjust_pvalue(method = "bonferroni") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 -8.54 46.4 55.0 bw_g… HF LF 12 12 -3.23 0.00389
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = OUTER.VAR, dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = OUTER.VAR)
stat.out$y.position <- max(stat.in$y.position)*1.1
# Sort dat.clean
dat.clean <- dat.clean[order(dat.clean$feedtreat),]
# Create plot
p <- ggboxplot(dat.clean, x = OUTER.VAR, y = OUTCOME,
color = PREDICTOR,
fill = PREDICTOR,
add = "jitter",
add.params = list(size = 1)) +
scale_fill_manual(values = params$COL1, name = "Group", labels = c("HF_CTRL" = "HF-CTRL","HF_PFOS" = "HF-PFOS","LF_CTRL" = "LF-CTRL","LF_PFOS" = "LF-PFOS")) +
scale_color_manual(values = c("black","black","black","black")) +
scale_y_continuous(name = "Bodyweight gain",limits = c(30,80),breaks = seq(30,80,10), labels = function(x) paste0(x, "%")) +
guides(color = "none") +
theme(axis.title.x = element_blank())
p <- p + stat_pvalue_manual(stat.in, label = "p.format",tip.length = 0, hide.ns = FALSE)+
stat_pvalue_manual(stat.out, label = "p.format", tip.length = 0, hide.ns = FALSE)
p# Plot for saving without legend
p2 <- p + theme(legend.position = "none")
# Output plot
ggsave(filename = paste0("plots/animal_data/weight/",OUTCOME,"_plot.png"), p2, device = "png", dpi = 300, units = "mm", width = 100, height = 100)
ggsave(filename = paste0("plots/animal_data/weight/",OUTCOME,"_plot.pdf"), p2, device = "pdf", dpi = 300, units = "mm", width = 100, height = 100)
# clear the environment and release memory
rm(list = ls(all.names = TRUE)) #will clear all objects includes hidden objects.
invisible(gc()) #free up memory and report the memory usage.5.3 Body weight gain - Day 8-21 (n = 24)
This section will prepare to perform the data analysis for body weight gain
5.3.1 Prepare data
This section sets the variables to be used and prepares the data if necessary.
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Subset
dat.clean <- subset(dat, !is.na(bw_gain821))
# Set names of variables
PREDICTOR <- "feedtreat"#c("treatment","pfos","van")
OUTCOME <- "bw_gain821"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 4 × 5
## feedtreat variable n mean sd
## <chr> <fct> <dbl> <dbl> <dbl>
## 1 HF_CTRL bw_gain821 6 19.5 4.42
## 2 HF_PFOS bw_gain821 6 22.0 5.08
## 3 LF_CTRL bw_gain821 6 25.2 4.55
## 4 LF_PFOS bw_gain821 6 23.9 4.47
# Create plot
bxp <- dat.clean %>%
ggboxplot(x = if_else(length(PREDICTOR) > 1, PREDICTOR[2],PREDICTOR[1]),
y = OUTCOME,
color = PREDICTOR[1],
facet.by = if(length(PREDICTOR) == 3) PREDICTOR[3],
palette = params$COL)
bxp# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 4 × 79
## feedtreat rat_org rat_name dissection cage treatment feed feedtreatday
## <chr> <chr> <chr> <chr> <int> <chr> <chr> <chr>
## 1 HF_CTRL R36 R36 d21 18 CTRL HF HF_CTRL_d21
## 2 HF_PFOS R46 R46 d21 23 PFOS HF HF_PFOS_d21
## 3 LF_PFOS R19 R19 d21 10 PFOS LF LF_PFOS_d21
## 4 LF_PFOS R23 R23 d21 12 PFOS LF LF_PFOS_d21
## # ℹ 71 more variables: bw_minus18 <dbl>, bw_0 <dbl>, bw_1 <int>, bw_2 <int>,
## # bw_3 <int>, bw_4 <int>, bw_5 <int>, bw_6 <int>, bw_7 <int>, bw_8 <int>,
## # bw_12 <dbl>, bw_16 <dbl>, bw_21 <dbl>, bw_gain08 <dbl>, bw_gain021 <dbl>,
## # bw_gain821 <dbl>, bloodvol_8 <dbl>, bloodvol_16 <dbl>, bloodvol_21 <dbl>,
## # cecum_wt <dbl>, cecum_wtbw <dbl>, cecum_norm <dbl>, liver_wt <dbl>,
## # liver_wtbw <dbl>, liver_norm <dbl>, brain_wt_estimate <dbl>,
## # transit_0 <int>, transit_7 <int>, transit_20 <int>, dose_total_ml <dbl>, …
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.955 0.348
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 3 20 0.0776 0.971
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
This shows that body weight gain data has two outliers, has equal variance and is normally distributed without the outliers according to Shapiro-Wilk test. Therefore we use a one-way ANOVA test with Tukey’s honest significance test.
5.3.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 feedtreat 3 20 1.716 0.196 0.205
Perform posthoc test
A significant one-way ANOVA is generally followed up by Tukey post-hoc tests to perform multiple pairwise comparisons between groups. When running relaxed Welch one-way test, the Games-Howell post hoc test or pairwise t-tests (with no assumption of equal variances) can be used to compare all possible combinations of group differences.
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 6 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj p.adj.signif
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 feedt… HF_CT… HF_PF… 0 2.51 -4.99 10.0 0.786 ns
## 2 feedt… HF_CT… LF_CT… 0 5.71 -1.79 13.2 0.177 ns
## 3 feedt… HF_CT… LF_PF… 0 4.40 -3.09 11.9 0.378 ns
## 4 feedt… HF_PF… LF_CT… 0 3.20 -4.29 10.7 0.637 ns
## 5 feedt… HF_PF… LF_PF… 0 1.89 -5.60 9.39 0.893 ns
## 6 feedt… LF_CT… LF_PF… 0 -1.31 -8.80 6.19 0.961 ns
5.3.3 Create figure
# Set variables for inner and outer analysis, and variable for facet
INNER.VAR <- "treatment"
OUTER.VAR <- "feed"
FACETVAR <- "dissection"
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(.data[[OUTER.VAR]]) %>%
t_test(as.formula(paste(OUTCOME,"~",INNER.VAR, sep = " ")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
# adjust_pvalue(method = "bonferroni") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## feed estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 HF -2.51 19.5 22.0 bw_gai… CTRL PFOS 6 6 -0.912
## 2 LF 1.31 25.2 23.9 bw_gai… CTRL PFOS 6 6 0.502
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
# group_by(.data[[FACETVAR]]) %>%
t_test(as.formula(paste(OUTCOME,"~", OUTER.VAR, sep = " ")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
# adjust_pvalue(method = "bonferroni") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 -3.80 20.8 24.6 bw_ga… HF LF 12 12 -2.05 0.0525
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = OUTER.VAR, dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = OUTER.VAR)
stat.out$y.position <- max(stat.in$y.position)*1.1
# Sort dat.clean
dat.clean <- dat.clean[order(dat.clean$feedtreat),]
# Create plot
p <- ggboxplot(dat.clean, x = OUTER.VAR, y = OUTCOME,
color = PREDICTOR,
fill = PREDICTOR,
add = "jitter",
add.params = list(size = 1)) +
scale_fill_manual(values = params$COL1, name = "Group", labels = c("HF_CTRL" = "HF-CTRL","HF_PFOS" = "HF-PFOS","LF_CTRL" = "LF-CTRL","LF_PFOS" = "LF-PFOS")) +
scale_color_manual(values = c("black","black","black","black")) +
scale_y_continuous(name = "Bodyweight gain",limits = c(10,40),breaks = seq(10,40,5), labels = function(x) paste0(x, "%")) +
guides(color = "none") +
theme(axis.title.x = element_blank())
p <- p + stat_pvalue_manual(stat.in, label = "p.format",tip.length = 0, hide.ns = FALSE)+
stat_pvalue_manual(stat.out, label = "p.format", tip.length = 0, hide.ns = FALSE)
p# Plot for saving without legend
p2 <- p + theme(legend.position = "none")
# Output plot
ggsave(filename = paste0("plots/animal_data/weight/",OUTCOME,"_plot.png"), p2, device = "png", dpi = 300, units = "mm", width = 100, height = 100)
ggsave(filename = paste0("plots/animal_data/weight/",OUTCOME,"_plot.pdf"), p2, device = "pdf", dpi = 300, units = "mm", width = 100, height = 100)
# clear the environment and release memory
rm(list = ls(all.names = TRUE)) #will clear all objects includes hidden objects.
invisible(gc()) #free up memory and report the memory usage.5.4 Body weight over time
This section will prepare data analysis and illustration of body weight data per rat over the course of this study. Final plot shows a normalised weight over time (bw day x / bw day 0) while rate of growth is calculated based on true weight data to produce a rate of g/day.
5.4.1 Prepare data and growth rates
# Load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Set parameters
PREDICTOR <- c("bw_time_n","treatment","feed")
OUTCOME <- "wt_n"
SUBJECT <- "rat_name"
# Create data frame for data representation
dat.clean <- dat %>% select(rat_name, feed, treatment, feedtreat, dissection, bw_0, bw_1, bw_2, bw_3, bw_4, bw_5, bw_6, bw_7, bw_8, bw_12, bw_16, bw_21)
# Normalise data
dat.clean <- dat.clean %>% mutate(bw_0_n = bw_0 / bw_0, bw_1_n = bw_1 / bw_0, bw_2_n = bw_2 / bw_0, bw_3_n = bw_3 / bw_0, bw_4_n = bw_4 / bw_0, bw_5_n = bw_5 / bw_0, bw_6_n = bw_6 / bw_0, bw_7_n = bw_7 / bw_0, bw_8_n = bw_8 / bw_0, bw_12_n = bw_12 / bw_0, bw_16_n = bw_16 / bw_0, bw_21_n = bw_21 / bw_0)
# Pivot longer
dat.bwn <- dat.clean %>%
pivot_longer(., cols = c(bw_0_n, bw_1_n, bw_2_n, bw_3_n, bw_4_n, bw_5_n, bw_6_n, bw_7_n, bw_8_n, bw_12_n, bw_16_n, bw_21_n), names_to = "bw_time_n", values_to = "wt_n")
dat.bw <- dat.clean %>%
pivot_longer(., cols = c(bw_0, bw_1, bw_2, bw_3, bw_4, bw_5, bw_6, bw_7, bw_8, bw_12, bw_16, bw_21), names_to = "bw_time", values_to = "wt")
# Create column for day of sampling (numeric)
dat.bwn <- dat.bwn %>% mutate("day" = case_when(bw_time_n == "bw_0_n" ~ 0,
bw_time_n == "bw_1_n" ~ 1,
bw_time_n == "bw_2_n" ~ 2,
bw_time_n == "bw_3_n" ~ 3,
bw_time_n == "bw_4_n" ~ 4,
bw_time_n == "bw_5_n" ~ 5,
bw_time_n == "bw_6_n" ~ 6,
bw_time_n == "bw_7_n" ~ 7,
bw_time_n == "bw_8_n" ~ 8,
bw_time_n == "bw_12_n" ~ 12,
bw_time_n == "bw_16_n" ~ 16,
bw_time_n == "bw_21_n" ~ 21))
# Create column for day of sampling (numeric)
dat.bw <- dat.bw %>% mutate("day" = case_when(bw_time == "bw_0" ~ 0,
bw_time == "bw_1" ~ 1,
bw_time == "bw_2" ~ 2,
bw_time == "bw_3" ~ 3,
bw_time == "bw_4" ~ 4,
bw_time == "bw_5" ~ 5,
bw_time == "bw_6" ~ 6,
bw_time == "bw_7" ~ 7,
bw_time == "bw_8" ~ 8,
bw_time == "bw_12" ~ 12,
bw_time == "bw_16" ~ 16,
bw_time == "bw_21" ~ 21))
# Order dataframe for analysis
dat.bwn <- dat.bwn[order(dat.bw$day),]
# Remove rows with NA
dat.bwn <- subset(dat.bwn, !is.na(wt_n))
dat.bw <- subset(dat.bw, !is.na(wt))
# Calculate regression lines per treatment group
reg_lines <- dat.bw %>%
group_by(feedtreat) %>%
summarize(slope = coef(lm(wt ~ day))[2],
intercept = coef(lm(wt ~ day))[1])
# Calculate regression lines per rat over time
rl_rats <- dat.bw %>%
group_by(rat_name) %>%
summarize(slope = coef(lm(wt ~ day))[2],
intercept = coef(lm(wt ~ day))[1]) %>%
cbind(data.frame(feedtreat = rep(c("LF_CTRL","LF_PFOS","HF_CTRL","HF_PFOS"), each = 12),
feed = rep(c("LF","HF"), each = 24),
treatment = rep(c("CTRL","PFOS"), each = 12, times = 2),
day = rep(c("d8","d21"), each = 6, times = 4)))
# Build the linear model
model <- lm(slope ~ feedtreat, data = rl_rats)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.952 0.0472
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 3 44 0.220 0.882
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 slope 48 7.49 3 0.0579 Kruskal-Wallis
# Posthoc Dunn's test
pwc2 <- rl_rats %>%
dunn_test(slope ~ feedtreat, p.adjust.method = "fdr")
pwc2## # A tibble: 6 × 9
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 slope HF_CTRL HF_PFOS 12 12 -0.190 0.850 0.850 ns
## 2 slope HF_CTRL LF_CTRL 12 12 2.01 0.0442 0.133 ns
## 3 slope HF_CTRL LF_PFOS 12 12 1.62 0.106 0.158 ns
## 4 slope HF_PFOS LF_CTRL 12 12 2.20 0.0277 0.133 ns
## 5 slope HF_PFOS LF_PFOS 12 12 1.81 0.0706 0.141 ns
## 6 slope LF_CTRL LF_PFOS 12 12 -0.394 0.694 0.833 ns
5.4.2 Statistical analysis
Based on the above tests of the regression for four groups we can analyse the data using Kruskal-Wallis with posthoc Dunn’s test.
# Set variables for inner and outer analysis, and variable for facet
INNER.VAR <- "treatment"
OUTER.VAR <- "feed"
FACETVAR <- "day"
# Statistics for overall data
stat.in2 <- rl_rats %>%
group_by(.data[[OUTER.VAR]]) %>%
wilcox_test(as.formula(paste("slope ~",INNER.VAR, sep = " "))) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj") %>%
p_format("p.adj", accuracy = 0.0001, trailing.zero = TRUE, new.col = TRUE)
stat.in2## # A tibble: 2 × 11
## feed .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 HF slope CTRL PFOS 12 12 73 0.977 0.977 ns
## 2 LF slope CTRL PFOS 12 12 79 0.713 0.977 ns
## # ℹ 1 more variable: p.adj.format <chr>
stat.out2 <- rl_rats %>%
wilcox_test(as.formula(paste("slope ~",OUTER.VAR, sep = " "))) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj") %>%
p_format("p.adj", accuracy = 0.0001, trailing.zero = TRUE, new.col = TRUE)
stat.out2## # A tibble: 1 × 10
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 slope HF LF 24 24 157 0.00633 0.00633 **
## # ℹ 1 more variable: p.adj.format <chr>
## Calculate positions statistics on plot
stat.in2 <- stat.in2 %>% add_xy_position(x = OUTER.VAR, dodge = 0.8)
stat.out2 <- stat.out2 %>% add_xy_position(x = OUTER.VAR, dodge = 0.9)
stat.out2$y.position <- max(stat.in2$y.position)*1.1
# Sort dat.clean
rl_rats <- rl_rats[order(rl_rats$feedtreat),]
# Visualise growth rates per group with statistics
p <- rl_rats %>%
ggboxplot(x = "feed",
y = "slope",
color = "feedtreat",
palette = params$COL1)
p2 <- p + stat_pvalue_manual(stat.in2, label = "p.adj.format",tip.length = 0, hide.ns = FALSE) +
stat_pvalue_manual(stat.out2, label = "p.adj.format",tip.length = 0, hide.ns = FALSE) +
scale_y_continuous(expand = expansion(mult = c(0,0.1)))
p2# Output plot
ggsave(filename = paste0("plots/animal_data/weight/bodyweight_slope_combined_plot.png"), p2, device = "png", dpi = 300, units = "mm", width = 100, height = 100)
ggsave(filename = paste0("plots/animal_data/weight/bodyweight_slope_combined_plot.pdf"), p2, device = "pdf", dpi = 300, units = "mm", width = 100, height = 100)
# Statistics for facet by day
stat.in1 <- rl_rats %>%
group_by(.data[[OUTER.VAR]],.data[[FACETVAR]]) %>%
wilcox_test(as.formula(paste("slope ~",INNER.VAR, sep = " "))) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj") %>%
p_format("p.adj", accuracy = 0.0001, trailing.zero = TRUE, new.col = TRUE)
stat.in1## # A tibble: 4 × 12
## feed day .y. group1 group2 n1 n2 statistic p p.adj
## * <chr> <chr> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl>
## 1 HF d21 slope CTRL PFOS 6 6 9 0.18 0.36
## 2 HF d8 slope CTRL PFOS 6 6 24 0.394 0.394
## 3 LF d21 slope CTRL PFOS 6 6 29 0.0931 0.36
## 4 LF d8 slope CTRL PFOS 6 6 12 0.394 0.394
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
stat.out1 <- rl_rats %>%
group_by(.data[[FACETVAR]]) %>%
wilcox_test(as.formula(paste("slope ~",OUTER.VAR, sep = " "))) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj") %>%
p_format("p.adj", accuracy = 0.0001, trailing.zero = TRUE, new.col = TRUE)
stat.out1## # A tibble: 2 × 11
## day .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 d21 slope HF LF 12 12 14 0.000371 0.000742 ***
## 2 d8 slope HF LF 12 12 55 0.347 0.347 ns
## # ℹ 1 more variable: p.adj.format <chr>
## Calculate positions statistics on plot
stat.in1 <- stat.in1 %>% add_xy_position(x = OUTER.VAR, dodge = 0.8)
stat.out1 <- stat.out1 %>% add_xy_position(x = OUTER.VAR, dodge = 0.9)
stat.out1$y.position <- max(stat.in1$y.position)*1.1
# Sort dat.clean
rl_rats <- rl_rats[order(rl_rats$feedtreat),]
# Visualise growth rates per group with statistics
p <- rl_rats %>%
ggboxplot(x = "feed",
y = "slope",
color = "feedtreat",
palette = params$COL1,
facet.by = "day")
p1 <- p + stat_pvalue_manual(stat.in1, label = "p.adj.format",tip.length = 0, hide.ns = FALSE) +
stat_pvalue_manual(stat.out1, label = "p.adj.format",tip.length = 0, hide.ns = FALSE) +
scale_y_continuous(expand = expansion(mult = c(0,0.1)))
p1# Output plot
ggsave(filename = paste0("plots/animal_data/weight/bodyweight_slope_",FACETVAR,"_plot.png"), p2, device = "png", dpi = 300, units = "mm", width = 100, height = 100)
ggsave(filename = paste0("plots/animal_data/weight/bodyweight_slope_",FACETVAR,"_plot.pdf"), p2, device = "pdf", dpi = 300, units = "mm", width = 100, height = 100)5.4.3 Create figure
# Mean and SD for growth rates for plotting
rl_rats_msd <- rl_rats %>%
group_by(feedtreat) %>% get_summary_stats(!!sym("slope"), type = "mean_sd")
# Slope texts for plot
slope_text <- data.frame(label = c(paste0("Rate = ",round(rl_rats_msd$mean[1],2),"(",round(rl_rats_msd$sd[1],2),") g/day"),
paste0("Rate = ",round(rl_rats_msd$mean[2],2),"(",round(rl_rats_msd$sd[2],2),") g/day"),
paste0("Rate = ",round(rl_rats_msd$mean[3],2),"(",round(rl_rats_msd$sd[3],2),") g/day"),
paste0("Rate = ",round(rl_rats_msd$mean[4],2),"(",round(rl_rats_msd$sd[4],2),") g/day")),
feedtreat = names(table(dat.bw$feedtreat)),
x = c(rep(15, times = 4)), y = c(rep(1.15, times = 4)))
# Summary samples in groups
dat.bwn %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 48 × 7
## feed treatment bw_time_n variable n mean sd
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl>
## 1 HF CTRL bw_0_n wt_n 12 1 0
## 2 LF CTRL bw_0_n wt_n 12 1 0
## 3 HF PFOS bw_0_n wt_n 12 1 0
## 4 LF PFOS bw_0_n wt_n 12 1 0
## 5 HF CTRL bw_12_n wt_n 6 1.30 0.051
## 6 LF CTRL bw_12_n wt_n 6 1.35 0.043
## 7 HF PFOS bw_12_n wt_n 6 1.31 0.029
## 8 LF PFOS bw_12_n wt_n 6 1.32 0.02
## 9 HF CTRL bw_16_n wt_n 6 1.38 0.045
## 10 LF CTRL bw_16_n wt_n 6 1.48 0.047
## # ℹ 38 more rows
# Setup rectangles
rec.df <- data.frame(x0 = -0.5, x1 = 0.5, x2 = 7.5, x3 = 21.5, y1 = 1.58, y2 = 1.6809, c0 = "a", c1 = "b", c2 = "c", t0 = "T0", t1 = "Dosing period", t2 = "Wash-out period")
# Generate plot
p <- ggplot(data = dat.bwn, aes(x = day, y = wt_n, fill = feedtreat)) +
geom_rect(data = rec.df, mapping = aes(xmin = x0, xmax = x1, ymin = y1, ymax = y2, fill = c0), fill = "#f0f0f0", inherit.aes = FALSE) +
geom_text(data = rec.df, aes(x = x0+(x1-x0)/2, y = y1+(y2-y1)/2, label = t0), size = 2.5, inherit.aes = FALSE) +
geom_rect(data = rec.df, mapping = aes(xmin = x1, xmax = x2, ymin = y1, ymax = y2, fill = c1), fill = "#ffffa0", inherit.aes = FALSE) +
geom_text(data = rec.df, aes(x = x1+(x2-x1)/2, y = y1+(y2-y1)/2, label = t1), size = 2.5, inherit.aes = FALSE) +
geom_rect(data = rec.df, mapping = aes(xmin = x2, xmax = x3, ymin = y1, ymax = y2, fill = c2), fill = "#ffd0d0", inherit.aes = FALSE) +
geom_text(data = rec.df, aes(x = x2+(x3-x2)/2, y = y1+(y2-y1)/2, label = t2), size = 2.5, inherit.aes = FALSE) +
geom_vline(data = NULL, xintercept = 8, linetype = "dashed", color = "#909090") +
geom_vline(data = NULL, xintercept = 21, linetype = "dashed", color = "#909090") +
geom_line(aes(group = rat_name, color = feedtreat), stat = "identity", alpha = 0.6) +
geom_smooth(aes(group = feedtreat, color = feedtreat), color = "#090909", method = "lm", se = FALSE, size = 0.5, fullrange = TRUE, linetype = "dashed") +
geom_boxplot(aes(group = day), outlier.shape = NA) +
geom_point(size = 0.5) +
scale_fill_manual(values = params$COL1, labels = c("HF-CTRL","HF-PFOS","LF-CTRL","LF-PFOS"), name = "Groups") +
scale_color_manual(values = params$COL1) +
scale_y_continuous(name = "Body weight ratio", limits = c(0.9,1.7), breaks = seq(1,1.7,0.2)) +
scale_x_continuous(name = "Day", breaks = c(0,1,2,3,4,5,6,7,8,12,16,21)) +
theme_pubr() +
guides(color = "none", alpha = "none") +
facet_wrap(.~feedtreat, labeller = labeller(feedtreat = c("LF_CTRL" = "LF-CTRL","LF_PFOS" = "LF-PFOS","HF_CTRL" = "HF-CTRL","HF_PFOS" = "HF-PFOS"))) +
geom_text(data = slope_text, aes(x = x, y = y, label = label), position = position_dodge(width = 0.9), size = 3.5)## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `geom_smooth()` using formula = 'y ~ x'
# Save plot
suppressMessages(ggsave(filename = "plots/animal_data/weight/bodyweight_norm_over_time.png", plot = p, device = "png", dpi = 300, units = "mm", height = 150, width = 260))
suppressMessages(ggsave(filename = "plots/animal_data/weight/bodyweight_norm_over_time.pdf", plot = p, device = "pdf", dpi = 300, units = "mm", height = 150, width = 260))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)) #will clear all objects includes hidden objects.
invisible(gc()) #free up memory and report the memory usage.5.5 Cecum weight
This section will prepare to perform the data analysis for cecum weight-to-body weight ratio data presented as normalised data for easy interpretation. Data is normalised after no fiber group control on respective days,
5.5.1 Prepare data
This section sets the variables to be used and prepares the data if necessary.
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
dat.clean <- subset(dat, !is.na(cecum_norm))
# Set names of variables
PREDICTOR <- c("treatment","feed","dissection")
OUTCOME <- "cecum_wtbw"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 8 × 7
## dissection treatment feed variable n mean sd
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl>
## 1 d08 CTRL HF cecum_wtbw 6 19.6 4.34
## 2 d21 CTRL HF cecum_wtbw 6 17.5 3.31
## 3 d08 CTRL LF cecum_wtbw 6 6.82 2.28
## 4 d21 CTRL LF cecum_wtbw 6 6.85 1.30
## 5 d08 PFOS HF cecum_wtbw 6 19.4 3.73
## 6 d21 PFOS HF cecum_wtbw 6 18.9 2.39
## 7 d08 PFOS LF cecum_wtbw 6 6.96 1.09
## 8 d21 PFOS LF cecum_wtbw 6 7.02 1.29
# SUmmary of original weight in grams
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(cecum_wt, type = "mean_sd")## # A tibble: 8 × 7
## dissection treatment feed variable n mean sd
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl>
## 1 d08 CTRL HF cecum_wt 6 6.90 1.61
## 2 d21 CTRL HF cecum_wt 6 6.90 1.4
## 3 d08 CTRL LF cecum_wt 6 2.28 0.709
## 4 d21 CTRL LF cecum_wt 6 3.1 0.476
## 5 d08 PFOS HF cecum_wt 6 6.62 1.27
## 6 d21 PFOS HF cecum_wt 6 7.84 1.37
## 7 d08 PFOS LF cecum_wt 6 2.47 0.375
## 8 d21 PFOS LF cecum_wt 6 2.93 0.457
## # A tibble: 8 × 16
## dissection treatment feed variable n min max median q1 q3 iqr
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 CTRL HF cecum_wt 6 5.15 9.51 6.55 5.79 7.69 1.89
## 2 d21 CTRL HF cecum_wt 6 5.57 9.03 6.47 5.83 7.80 1.97
## 3 d08 CTRL LF cecum_wt 6 1.16 3.12 2.45 1.91 2.69 0.775
## 4 d21 CTRL LF cecum_wt 6 2.42 3.50 3.32 2.74 3.45 0.707
## 5 d08 PFOS HF cecum_wt 6 4.72 8.56 6.60 6.18 7.06 0.884
## 6 d21 PFOS HF cecum_wt 6 6.41 10.1 7.4 6.98 8.54 1.56
## 7 d08 PFOS LF cecum_wt 6 1.99 3.11 2.43 2.30 2.56 0.268
## 8 d21 PFOS LF cecum_wt 6 2.57 3.59 2.72 2.58 3.28 0.69
## # ℹ 5 more variables: mad <dbl>, mean <dbl>, sd <dbl>, se <dbl>, ci <dbl>
# Create plot
bxp <- dat.clean %>%
ggboxplot(x = if_else(length(PREDICTOR) > 1, PREDICTOR[2],PREDICTOR[1]),
y = OUTCOME,
color = PREDICTOR[1],
facet.by = if(length(PREDICTOR) == 3) PREDICTOR[3],
palette = "jco")
bxp# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## [1] dissection treatment feed rat_org
## [5] rat_name cage feedtreat feedtreatday
## [9] bw_minus18 bw_0 bw_1 bw_2
## [13] bw_3 bw_4 bw_5 bw_6
## [17] bw_7 bw_8 bw_12 bw_16
## [21] bw_21 bw_gain08 bw_gain021 bw_gain821
## [25] bloodvol_8 bloodvol_16 bloodvol_21 cecum_wt
## [29] cecum_wtbw cecum_norm liver_wt liver_wtbw
## [33] liver_norm brain_wt_estimate transit_0 transit_7
## [37] transit_20 dose_total_ml pfos_total_mg pfos_liver_ugg
## [41] pfos_liver_mg pfos_liver8_pct pfos_brain_ugg pfos_brain_uggbw
## [45] pfos_brain_ug pfos_brain_pct pfos_serum8_ugml pfos_serum8_mg
## [49] pfos_serum8_pct pfos_serum16_ugml pfos_serum16_mg pfos_serum16_pct
## [53] pfos_serum21_ugml pfos_serum21_mg pfos_serum21_pct pfos_feces8_ugg
## [57] pfos_feces12_ugg pfos_feces16_ugg pfos_feces21_ugg pfos_cecum_ugg
## [61] pfos_urine8_ugml pfos_urine16_ugml pfos_urine21_ugml pH_je_up
## [65] pH_je_down pH_ileum pH_cecum acetic
## [69] formic propanoic m2_propanoic butanoic
## [73] m3_butanoic pentanoic m4_pentanoic hexanoic
## [77] heptanoic is.outlier is.extreme
## <0 rækker> (eller 0-længde row.names)
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.983 0.719
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 7 40 1.73 0.130
This all shows that cecum weight data has three none-critical outliers, is normally distribution and has equal variance. Therefore we use a one-way ANOVA test with Tukey’s honest significance test to test data for all factors of interest, while using unpaired t-test for pairwise comparisons.
5.5.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 treatment 1 40 0.258 6.14e-01 0.006
## 2 feed 1 40 232.040 3.02e-18 * 0.853
## 3 dissection 1 40 0.620 4.36e-01 0.015
## 4 treatment:feed 1 40 0.100 7.54e-01 0.002
## 5 treatment:dissection 1 40 0.256 6.15e-01 0.006
## 6 feed:dissection 1 40 0.713 4.03e-01 0.018
## 7 treatment:feed:dissection 1 40 0.235 6.30e-01 0.006
ANOVA shows that feed has the only significant effect on the overall data.
Perform posthoc test
A significant one-way ANOVA is generally followed up by Tukey post-hoc tests to perform multiple pairwise comparisons between groups. When running relaxed Welch one-way test, the Games-Howell post hoc test or pairwise t-tests (with no assumption of equal variances) can be used to compare all possible combinations of group differences.
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 49 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 treatment CTRL PFOS 0 3.99e-1 -1.19 1.98 6.14e- 1
## 2 feed HF LF 0 -1.20e+1 -13.5 -10.4 4.64e-13
## 3 dissection d08 d21 0 -6.18e-1 -2.20 0.969 4.36e- 1
## 4 treatment:feed CTRL:… PFOS:… 0 6.47e-1 -2.33 3.62 9.37e- 1
## 5 treatment:feed CTRL:… CTRL:… 0 -1.17e+1 -14.7 -8.73 2.91e-12
## 6 treatment:feed CTRL:… PFOS:… 0 -1.16e+1 -14.5 -8.58 4.04e-12
## 7 treatment:feed PFOS:… CTRL:… 0 -1.24e+1 -15.3 -9.38 9.64e-13
## 8 treatment:feed PFOS:… PFOS:… 0 -1.22e+1 -15.2 -9.23 1.18e-12
## 9 treatment:feed CTRL:… PFOS:… 0 1.51e-1 -2.82 3.13 9.99e- 1
## 10 treatment:diss… CTRL:… PFOS:… 0 1.15e-3 -2.97 2.98 1 e+ 0
## # ℹ 39 more rows
## # ℹ 1 more variable: p.adj.signif <chr>
5.5.3 Nested analysis & Figure
Testing two variables are used when there is a nested aspect in the analysis, for example difference in treatment at each timepoint, that would have the timepoint as the outer variable and treatment as the inner variable
# Set variables for inner and outer analysis, and variable for facet
INNER.VAR <- "treatment"
OUTER.VAR <- "feed"
FACETVAR <- "dissection"
# Remove samples with incomplete metadata
dat.clean <- dat.clean[!is.na(dat.clean[,INNER.VAR]) & !is.na(dat.clean[,OUTER.VAR]),]
# Set variables as factors
dat.clean[,OUTER.VAR] <- as.factor(dat.clean[,OUTER.VAR])
dat.clean[,INNER.VAR] <- as.factor(dat.clean[,INNER.VAR])
dat.clean[,FACETVAR] <- as.factor(dat.clean[,FACETVAR])
# Cecum_norm
fit <- aov(as.formula(paste(OUTCOME,"~", OUTER.VAR,"*",INNER.VAR, sep = " ")), data = dat.clean)
anova(fit)## Analysis of Variance Table
##
## Response: cecum_wtbw
## Df Sum Sq Mean Sq F value Pr(>F)
## feed 1 1715.39 1715.39 244.1094 <2e-16 ***
## treatment 1 1.91 1.91 0.2713 0.6051
## feed:treatment 1 0.74 0.74 0.1050 0.7474
## Residuals 44 309.19 7.03
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = as.formula(paste(OUTCOME, "~", OUTER.VAR, "*", INNER.VAR, sep = " ")), data = dat.clean)
##
## $feed
## diff lwr upr p adj
## LF-HF -11.95613 -13.49838 -10.41389 0
##
## $treatment
## diff lwr upr p adj
## PFOS-CTRL 0.3986117 -1.143631 1.940854 0.6050505
##
## $`feed:treatment`
## diff lwr upr p adj
## LF:CTRL-HF:CTRL -11.7081226 -14.597642 -8.818603 0.0000000
## HF:PFOS-HF:CTRL 0.6466221 -2.242897 3.536142 0.9322867
## LF:PFOS-HF:CTRL -11.5575214 -14.447041 -8.668002 0.0000000
## HF:PFOS-LF:CTRL 12.3547447 9.465225 15.244264 0.0000000
## LF:PFOS-LF:CTRL 0.1506012 -2.738918 3.040121 0.9990233
## LF:PFOS-HF:PFOS -12.2041435 -15.093663 -9.314624 0.0000000
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(.data[[OUTER.VAR]], .data[[FACETVAR]]) %>%
t_test(as.formula(paste(OUTCOME,"~",INNER.VAR, sep = " ")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 4 × 19
## dissection feed estimate estimate1 estimate2 .y. group1 group2 n1 n2
## * <fct> <fct> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 d08 HF 0.132 19.6 19.4 cecum… CTRL PFOS 6 6
## 2 d21 HF -1.42 17.5 18.9 cecum… CTRL PFOS 6 6
## 3 d08 LF -0.134 6.82 6.96 cecum… CTRL PFOS 6 6
## 4 d21 LF -0.167 6.85 7.02 cecum… CTRL PFOS 6 6
## # ℹ 9 more variables: statistic <dbl>, p <dbl>, df <dbl>, conf.low <dbl>,
## # conf.high <dbl>, method <chr>, alternative <chr>, p.signif <chr>,
## # p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
group_by(.data[[FACETVAR]]) %>%
t_test(as.formula(paste(OUTCOME,"~", OUTER.VAR, sep = " ")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 2 × 18
## dissection estimate estimate1 estimate2 .y. group1 group2 n1 n2
## * <fct> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 d08 12.6 19.5 6.89 cecum_wtbw HF LF 12 12
## 2 d21 11.3 18.2 6.94 cecum_wtbw HF LF 12 12
## # ℹ 9 more variables: statistic <dbl>, p <dbl>, df <dbl>, conf.low <dbl>,
## # conf.high <dbl>, method <chr>, alternative <chr>, p.signif <chr>,
## # p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = OUTER.VAR, dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = OUTER.VAR)
stat.out$y.position <- max(stat.in$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = OUTER.VAR, y = "cecum_norm",
color = "feedtreat",
fill = "feedtreat",
add = "jitter",
add.params = list(size = 1),
panel.labs = list("dissection" = c("Day 8","Day 21")),
facet.by = "dissection") +
theme_pubr(legend = "top") +
scale_fill_manual(breaks = dat.clean$treatment, values = params$COL1) +
scale_color_manual(breaks = dat.clean$treatment, values = c("HF_CTRL" = "black","HF_PFOS" = "black","LF_CTRL" = "black","LF_PFOS" = "black")) +
scale_x_discrete(name = "Feed") +
guides(color = FALSE) +
theme(axis.title.x = element_blank())## Warning: The `<scale>` argument of `guides()` cannot be `FALSE`. Use "none" instead as
## of ggplot2 3.3.4.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
# Add p-values for inner and outer analysis to plot
p.stat <- p +
stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, label = "p.signif", tip.length = 0, hide.ns = TRUE, y.position = c(1.45,1.45)) +
scale_y_continuous(name ="Percentage from mean HF-CTRL", limits = c(0.15,1.5), breaks = seq(0,1.5,0.25), labels = function(x) paste0(x*100-100, "%"))
p.stat### Create output plot
suppressMessages(ggsave(filename = paste0("plots/animal_data/weight/cecum_weight_nested_",OUTER.VAR,"_",INNER.VAR,".png"), plot = p.stat, device = "png", units = "mm", width = 130, height = 80, dpi = 300))
suppressMessages(ggsave(filename = paste0("plots/animal_data/weight/cecum_weight_nested_",OUTER.VAR,"_",INNER.VAR,".pdf"), plot = p.stat, device = "pdf", units = "mm", width = 130, height = 80, dpi = 300))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())5.6 Liver weight
This section will prepare to perform the data analysis for liver weight-to-body weight data, presented as normalised data for easy interpretation.
5.6.1 Prepare data
This section sets the variables to be used and prepares the data if necessary.
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
dat.clean <- subset(dat, !is.na(cecum_norm))
# Set names of variables
PREDICTOR <- c("treatment","feed","dissection")
OUTCOME <- "liver_wtbw"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 8 × 7
## dissection treatment feed variable n mean sd
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl>
## 1 d08 CTRL HF liver_wtbw 6 46.9 2.73
## 2 d21 CTRL HF liver_wtbw 6 39.3 3.14
## 3 d08 CTRL LF liver_wtbw 6 46.3 3.37
## 4 d21 CTRL LF liver_wtbw 6 42.2 4.44
## 5 d08 PFOS HF liver_wtbw 6 49.1 3.90
## 6 d21 PFOS HF liver_wtbw 6 43.4 3.92
## 7 d08 PFOS LF liver_wtbw 6 51.6 3.35
## 8 d21 PFOS LF liver_wtbw 6 42.2 4.34
# SUmmary of original weight in grams
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(liver_wt, type = "mean_sd")## # A tibble: 8 × 7
## dissection treatment feed variable n mean sd
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl>
## 1 d08 CTRL HF liver_wt 6 16.6 2.42
## 2 d21 CTRL HF liver_wt 6 15.5 1.68
## 3 d08 CTRL LF liver_wt 6 15.7 2.40
## 4 d21 CTRL LF liver_wt 6 19.2 2.37
## 5 d08 PFOS HF liver_wt 6 16.8 1.99
## 6 d21 PFOS HF liver_wt 6 17.9 1.58
## 7 d08 PFOS LF liver_wt 6 18.6 3.38
## 8 d21 PFOS LF liver_wt 6 17.7 1.88
## # A tibble: 8 × 16
## dissection treatment feed variable n min max median q1 q3 iqr
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 CTRL HF liver_wt 6 14.3 19.9 15.8 14.9 18.5 3.61
## 2 d21 CTRL HF liver_wt 6 13.4 17.3 16.0 14.0 16.6 2.61
## 3 d08 CTRL LF liver_wt 6 13.0 18.5 15.6 13.6 17.7 4.11
## 4 d21 CTRL LF liver_wt 6 16.9 23.4 18.4 18.0 20.0 2.01
## 5 d08 PFOS HF liver_wt 6 13.5 18.9 16.7 16.2 18.3 2.07
## 6 d21 PFOS HF liver_wt 6 15.6 20.1 18.3 17.0 18.4 1.38
## 7 d08 PFOS LF liver_wt 6 15.1 24.2 17.3 16.6 20.2 3.60
## 8 d21 PFOS LF liver_wt 6 15.4 19.8 17.6 16.4 19.4 3.07
## # ℹ 5 more variables: mad <dbl>, mean <dbl>, sd <dbl>, se <dbl>, ci <dbl>
# Create plot
bxp <- dat.clean %>%
ggboxplot(x = if_else(length(PREDICTOR) > 1, PREDICTOR[2],PREDICTOR[1]),
y = OUTCOME,
color = PREDICTOR[1],
facet.by = if(length(PREDICTOR) == 3) PREDICTOR[3],
palette = "jco")
bxp# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 2 × 79
## dissection treatment feed rat_org rat_name cage feedtreat feedtreatday
## <chr> <chr> <chr> <chr> <chr> <int> <chr> <chr>
## 1 d08 PFOS HF R39 R39 20 HF_PFOS HF_PFOS_d08
## 2 d08 PFOS HF R43 R41 22 HF_PFOS HF_PFOS_d08
## # ℹ 71 more variables: bw_minus18 <dbl>, bw_0 <dbl>, bw_1 <int>, bw_2 <int>,
## # bw_3 <int>, bw_4 <int>, bw_5 <int>, bw_6 <int>, bw_7 <int>, bw_8 <int>,
## # bw_12 <dbl>, bw_16 <dbl>, bw_21 <dbl>, bw_gain08 <dbl>, bw_gain021 <dbl>,
## # bw_gain821 <dbl>, bloodvol_8 <dbl>, bloodvol_16 <dbl>, bloodvol_21 <dbl>,
## # cecum_wt <dbl>, cecum_wtbw <dbl>, cecum_norm <dbl>, liver_wt <dbl>,
## # liver_wtbw <dbl>, liver_norm <dbl>, brain_wt_estimate <dbl>,
## # transit_0 <int>, transit_7 <int>, transit_20 <int>, dose_total_ml <dbl>, …
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.980 0.559
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 7 40 0.225 0.977
This all shows that normalised cecum weight data has two outliers, is normally distribution and has equal variance. Therefore we use a one-way ANOVA test with Tukey’s honest significance test to test data for all factors of interest, while using unpaired t-test for pairwise comparisons.
5.6.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 treatment 1 40 7.564 9.00e-03 * 1.59e-01
## 2 feed 1 40 0.762 3.88e-01 1.90e-02
## 3 dissection 1 40 39.215 2.02e-07 * 4.95e-01
## 4 treatment:feed 1 40 0.059 8.09e-01 1.00e-03
## 5 treatment:dissection 1 40 0.627 4.33e-01 1.50e-02
## 6 feed:dissection 1 40 0.001 9.70e-01 3.47e-05
## 7 treatment:feed:dissection 1 40 2.967 9.30e-02 6.90e-02
ANOVA shows that treatment and day of dissection for the samples have significant effects on the overall data.
Perform posthoc test
A significant one-way ANOVA is generally followed up by Tukey post-hoc tests to perform multiple pairwise comparisons between groups. When running relaxed Welch one-way test, the Games-Howell post hoc test or pairwise t-tests (with no assumption of equal variances) can be used to compare all possible combinations of group differences.
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 49 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 treatment CTRL PFOS 0 2.93 0.777 5.08 8.9 e-3
## 2 feed HF LF 0 0.930 -1.22 3.08 3.88e-1
## 3 dissection d08 d21 0 -6.67 -8.83 -4.52 2.02e-7
## 4 treatment:feed CTRL:… PFOS:… 0 3.19 -0.850 7.23 1.65e-1
## 5 treatment:feed CTRL:… CTRL:… 0 1.19 -2.85 5.23 8.59e-1
## 6 treatment:feed CTRL:… PFOS:… 0 3.86 -0.178 7.90 6.55e-2
## 7 treatment:feed PFOS:… CTRL:… 0 -2.00 -6.04 2.04 5.51e-1
## 8 treatment:feed PFOS:… PFOS:… 0 0.671 -3.37 4.71 9.7 e-1
## 9 treatment:feed CTRL:… PFOS:… 0 2.67 -1.37 6.71 3.01e-1
## 10 treatment:disse… CTRL:… PFOS:… 0 3.77 -0.265 7.81 7.45e-2
## # ℹ 39 more rows
## # ℹ 1 more variable: p.adj.signif <chr>
Post hoc analysis however show only significant differences between groupings to be between overall treatment, overall dissection days, as well as cross-day comparisons.
5.6.3 Nested analysis & Figure
Testing two variables are used when there is a nested aspect in the analysis, for example difference in treatment at each timepoint, that would have the timepoint as the outer variable and treatment as the inner variable
# Set variables for inner and outer analysis, and variable for facet
INNER.VAR <- "treatment"
OUTER.VAR <- "feed"
FACETVAR <- "dissection"
# Remove samples with incomplete metadata
dat.clean <- dat.clean[!is.na(dat.clean[,INNER.VAR]) & !is.na(dat.clean[,OUTER.VAR]),]
# Set variables as factors
dat.clean[,OUTER.VAR] <- as.factor(dat.clean[,OUTER.VAR])
dat.clean[,INNER.VAR] <- as.factor(dat.clean[,INNER.VAR])
dat.clean[,FACETVAR] <- as.factor(dat.clean[,FACETVAR])
# Cecum_norm
fit <- aov(as.formula(paste(OUTCOME,"~", OUTER.VAR,"*",INNER.VAR, sep = " ")), data = dat.clean)
anova(fit)## Analysis of Variance Table
##
## Response: liver_wtbw
## Df Sum Sq Mean Sq F value Pr(>F)
## feed 1 10.38 10.384 0.4050 0.52780
## treatment 1 103.04 103.039 4.0190 0.05117 .
## feed:treatment 1 0.80 0.804 0.0314 0.86027
## Residuals 44 1128.06 25.638
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## Tukey multiple comparisons of means
## 95% family-wise confidence level
##
## Fit: aov(formula = as.formula(paste(OUTCOME, "~", OUTER.VAR, "*", INNER.VAR, sep = " ")), data = dat.clean)
##
## $feed
## diff lwr upr p adj
## LF-HF 0.9302309 -2.015571 3.876032 0.5278019
##
## $treatment
## diff lwr upr p adj
## PFOS-CTRL 2.930289 -0.01551291 5.87609 0.0511665
##
## $`feed:treatment`
## diff lwr upr p adj
## LF:CTRL-HF:CTRL 1.1890424 -4.330161 6.708246 0.9389701
## HF:PFOS-HF:CTRL 3.1891000 -2.330103 8.708303 0.4213654
## LF:PFOS-HF:CTRL 3.8605195 -1.658684 9.379723 0.2566549
## HF:PFOS-LF:CTRL 2.0000577 -3.519146 7.519261 0.7684275
## LF:PFOS-LF:CTRL 2.6714771 -2.847726 8.190680 0.5725927
## LF:PFOS-HF:PFOS 0.6714195 -4.847784 6.190623 0.9879985
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(.data[[OUTER.VAR]], .data[[FACETVAR]]) %>%
t_test(as.formula(paste(OUTCOME,"~",INNER.VAR, sep = " ")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 4 × 19
## dissection feed estimate estimate1 estimate2 .y. group1 group2 n1 n2
## * <fct> <fct> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 d08 HF -2.20 46.9 49.1 liver… CTRL PFOS 6 6
## 2 d21 HF -4.18 39.3 43.4 liver… CTRL PFOS 6 6
## 3 d08 LF -5.35 46.3 51.6 liver… CTRL PFOS 6 6
## 4 d21 LF 0.00726 42.2 42.2 liver… CTRL PFOS 6 6
## # ℹ 9 more variables: statistic <dbl>, p <dbl>, df <dbl>, conf.low <dbl>,
## # conf.high <dbl>, method <chr>, alternative <chr>, p.signif <chr>,
## # p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
group_by(.data[[FACETVAR]]) %>%
t_test(as.formula(paste(OUTCOME,"~", OUTER.VAR, sep = " ")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 2 × 18
## dissection estimate estimate1 estimate2 .y. group1 group2 n1 n2
## * <fct> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 d08 -0.970 48.0 49.0 liver_wtbw HF LF 12 12
## 2 d21 -0.891 41.4 42.2 liver_wtbw HF LF 12 12
## # ℹ 9 more variables: statistic <dbl>, p <dbl>, df <dbl>, conf.low <dbl>,
## # conf.high <dbl>, method <chr>, alternative <chr>, p.signif <chr>,
## # p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = OUTER.VAR, dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = OUTER.VAR)
stat.out$y.position <- max(stat.in$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = OUTER.VAR, y = "liver_norm",
color = "feedtreat",
fill = "feedtreat",
add = "jitter",
add.params = list(size = 1),
panel.labs = list("dissection" = c("Day 8","Day 21")),
facet.by = "dissection") +
theme_pubr(legend = "top") +
scale_fill_manual(breaks = dat.clean$treatment, values = params$COL1) +
scale_color_manual(breaks = dat.clean$treatment, values = c("HF_CTRL" = "black","HF_PFOS" = "black","LF_CTRL" = "black","LF_PFOS" = "black")) +
scale_x_discrete(name = "Feed") +
guides(color = FALSE) +
theme(axis.title.x = element_blank())
p# Add p-values for inner and outer analysis to plot
p.stat <- p +
stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red", y.position = 1.28) +
stat_pvalue_manual(stat.out, label = "p.signif", tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name ="Percentage from mean HF-CTRL", expand = expansion(mult = c(0.01, 0.1)), limits = c(0.85,1.3), breaks = seq(0.8,1.3,0.1), labels = function(x) paste0(x*100-100, "%"))
p.stat### Create output plot
suppressMessages(ggsave(filename = paste0("plots/animal_data/weight/liver_weight_nested_",OUTER.VAR,"_",INNER.VAR,".png"), plot = p.stat, device = "png", units = "mm", width = 130, height = 80, dpi = 300))
suppressMessages(ggsave(filename = paste0("plots/animal_data/weight/liver_weight_nested_",OUTER.VAR,"_",INNER.VAR,".pdf"), plot = p.stat, device = "pdf", units = "mm", width = 130, height = 80, dpi = 300))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())6 PFOS QUANTITATIVE DATA
Following section handles data analysis of PFOS samples. Biological samples were extracted in acetonitrile and run on a LC-HRMS system using UPLC (Vanquish Flex, Thermo Fisher Scientific) coupled to an Orbitrap HRMS (Exploris 120, Thermo Fisher Scientific) against a linear PFOS standard curve and with internal MPFOS standard. Data presented here in ug/mL, ug/g and total mg are calculated from dilution factors and the original sample concentrations.
6.1 SYSTEMIC MEASUREMENTS
Following systemic measurements are analysed and presented here:
- Blood serum from day 8, 16, and 21
- Brain tissue from dissection days 8 and 21
- Liver tissue from dissection days 8 and 21
6.1.1 Blood serum
6.1.1.1 ug/mL
6.1.1.1.1 Prepare data
# Load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Set parameters
PREDICTOR <- c("feed","day")
OUTCOME <- "conc"
SUBJECT <- "rat_name"
# Create data frame for data representation
dat.clean <- dat %>% select(rat_name, feed, treatment, feedtreat, dissection, bw_8, bw_21, bloodvol_8, bloodvol_16, bloodvol_21, pfos_total_mg, pfos_serum8_ugml, pfos_serum16_ugml, pfos_serum21_ugml) %>%
pivot_longer(., cols = c(pfos_serum8_ugml, pfos_serum16_ugml, pfos_serum21_ugml), names_to = "pfos_day", values_to = "conc")
# Create column for day of sampling
dat.clean <- dat.clean %>%
mutate("day" = case_when(pfos_day == "pfos_serum8_ugml" ~ "d08",
pfos_day == "pfos_serum16_ugml" ~ "d16",
pfos_day == "pfos_serum21_ugml" ~ "d21"))
# Order dataframe for analysis
dat.clean <- dat.clean[order(dat.clean$day),]
# Remove rows with NA
dat.clean <- subset(dat.clean, !is.na(conc))
# Subset to only PFOS groups
dat.clean <- subset(dat.clean, dat.clean$treatment == "PFOS")
dat.clean## # A tibble: 48 × 14
## rat_name feed treatment feedtreat dissection bw_8 bw_21 bloodvol_8
## <chr> <chr> <chr> <chr> <chr> <int> <dbl> <dbl>
## 1 R13 LF PFOS LF_PFOS d08 373 NA 23.9
## 2 R14 LF PFOS LF_PFOS d08 390 NA 25.0
## 3 R15 LF PFOS LF_PFOS d08 341 NA 21.8
## 4 R16 LF PFOS LF_PFOS d08 299 NA 19.1
## 5 R17 LF PFOS LF_PFOS d08 322 NA 20.6
## 6 R18 LF PFOS LF_PFOS d08 423 NA 27.1
## 7 R19 LF PFOS LF_PFOS d21 344 403. 22.0
## 8 R20 LF PFOS LF_PFOS d21 357 442. 22.8
## 9 R21 LF PFOS LF_PFOS d21 342 422. 21.9
## 10 R22 LF PFOS LF_PFOS d21 349 432. 22.3
## # ℹ 38 more rows
## # ℹ 6 more variables: bloodvol_16 <dbl>, bloodvol_21 <dbl>,
## # pfos_total_mg <dbl>, pfos_day <chr>, conc <dbl>, day <chr>
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("feed","day","n","min","max","mean","sd","se")## # A tibble: 6 × 8
## feed day n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF d08 12 46.8 64.0 55.9 5.17 1.49
## 2 HF d16 6 39.6 50.4 45.7 3.78 1.54
## 3 HF d21 6 34.2 43.4 40.0 3.69 1.51
## 4 LF d08 12 51.5 66.7 58.4 4.37 1.26
## 5 LF d16 6 44.3 53.6 49.2 3.00 1.23
## 6 LF d21 6 36.3 51.1 42.3 5.12 2.09
Visualise
Create a boxplot of the data.
# Create plot
bxp <- dat.clean %>%
ggboxplot(x = if_else(length(PREDICTOR) > 1, PREDICTOR[2],PREDICTOR[1]),
y = OUTCOME,
color = PREDICTOR[1],
facet.by = if(length(PREDICTOR) == 3) PREDICTOR[3],
palette = "jco")
bxp
Assumptions and preliminary tests
The ANOVA tests assume the following characteristics about the data:
Independence of the observations. Each subject should belong to only one group. There is no relationship between the observations in each group.
This is already done for the whole projectNo significant outliers in the two groups
Normality. the data for each group should be approximately normally distributed.
Homogeneity of variances. the variance of the outcome variable should be equal in each group.
In this section, we’ll perform some preliminary tests to check whether these assumptions are met.
Identify outliers
Outliers can be easily identified using boxplot methods, implemented in
the R function identify_outliers() [rstatix package].
# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 3 × 16
## feed day rat_name treatment feedtreat dissection bw_8 bw_21 bloodvol_8
## <chr> <chr> <chr> <chr> <chr> <chr> <int> <dbl> <dbl>
## 1 LF d16 R23 PFOS LF_PFOS d21 337 442. 21.6
## 2 LF d16 R24 PFOS LF_PFOS d21 306 380. 19.6
## 3 LF d21 R23 PFOS LF_PFOS d21 337 442. 21.6
## # ℹ 7 more variables: bloodvol_16 <dbl>, bloodvol_21 <dbl>,
## # pfos_total_mg <dbl>, pfos_day <chr>, conc <dbl>, is.outlier <lgl>,
## # is.extreme <lgl>
Data contains three outliers. These do not change the outcome of the analysis and are left in.
Check normality
QQ plot and Shapiro-Wilk test of normality are used to analyze the model
residuals.
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.988 0.885
Data is Normally distributed.
Test homogneity of variance assumption
1. The residuals versus fits plot can be used to check the homogeneity
of variances.
- It’s also possible to use the Levene’s test to check the homogeneity of variances:
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 5 42 0.604 0.697
If the p-value of the Levene’s test is significant, it suggests that
there is a significant difference between the variances of the two
groups. In such case we should use Welch t-test, which doesn’t assume
the equality of the two variances (var.equal=FALSE). If the
Levene’s test is non-significant we can perform a Student t-test
(var.equal=TRUE).
This all shows that normalised cecum weight data has two outliers, is normally distribution and has equal variance. Therefore we use a one-way ANOVA test with Tukey’s honest significance test to test data for all factors of interest, while using unpaired t-test for pairwise comparisons.
6.1.1.1.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA, dv = conc, between = feed, within = day, wid = rat_name)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 feed 1 42 4.452 4.10e-02 * 0.096
## 2 day 2 42 56.842 1.13e-12 * 0.730
## 3 feed:day 2 42 0.073 9.30e-01 0.003
ANOVA shows that day and feed have significant effects on the overall data.
Perform posthoc test
A significant one-way ANOVA is generally followed up by Tukey post-hoc tests to perform multiple pairwise comparisons between groups. When running relaxed Welch one-way test, the Games-Howell post hoc test or pairwise t-tests (with no assumption of equal variances) can be used to compare all possible combinations of group differences.
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 19 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 feed HF LF 0 2.69 0.117 5.27 4.09e- 2
## 2 day d08 d16 0 -9.71 -13.5 -5.91 5.78e- 7
## 3 day d08 d21 0 -16.0 -19.8 -12.2 2.73e-12
## 4 day d16 d21 0 -6.29 -10.7 -1.90 3.27e- 3
## 5 feed:day HF:d08 LF:d08 0 2.50 -2.89 7.88 7.35e- 1
## 6 feed:day HF:d08 HF:d16 0 -10.2 -16.8 -3.62 4.82e- 4
## 7 feed:day HF:d08 LF:d16 0 -6.70 -13.3 -0.106 4.45e- 2
## 8 feed:day HF:d08 HF:d21 0 -15.9 -22.5 -9.28 1.16e- 7
## 9 feed:day HF:d08 LF:d21 0 -13.6 -20.2 -7.03 3.31e- 6
## 10 feed:day LF:d08 HF:d16 0 -12.7 -19.3 -6.12 1.27e- 5
## 11 feed:day LF:d08 LF:d16 0 -9.20 -15.8 -2.60 1.98e- 3
## 12 feed:day LF:d08 HF:d21 0 -18.4 -25.0 -11.8 3.01e- 9
## 13 feed:day LF:d08 LF:d21 0 -16.1 -22.7 -9.52 8.04e- 8
## 14 feed:day HF:d16 LF:d16 0 3.52 -4.10 11.1 7.39e- 1
## 15 feed:day HF:d16 HF:d21 0 -5.65 -13.3 1.96 2.52e- 1
## 16 feed:day HF:d16 LF:d21 0 -3.40 -11.0 4.21 7.65e- 1
## 17 feed:day LF:d16 HF:d21 0 -9.17 -16.8 -1.56 1.03e- 2
## 18 feed:day LF:d16 LF:d21 0 -6.92 -14.5 0.695 9.39e- 2
## 19 feed:day HF:d21 LF:d21 0 2.25 -5.36 9.87 9.49e- 1
## # ℹ 1 more variable: p.adj.signif <chr>
Posthoc analysis however show significant differences between to be between overall treatment, overall dissection days, as well as cross-day comparisons.
6.1.1.1.3 Nested analysis and Figure
# Set variables for inner and outer analyses
INNER.VAR <- "feed"
OUTER.VAR <- "day"
# Statistics costumed for facet plotting
## T-test comparison for inner variable
stat.in <- dat.clean %>%
group_by(day) %>%
t_test(conc ~ feed,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 3 × 18
## day estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 d08 -2.50 55.9 58.4 conc HF LF 12 12 -1.28
## 2 d16 -3.52 45.7 49.2 conc HF LF 6 6 -1.78
## 3 d21 -2.25 40.0 42.3 conc HF LF 6 6 -0.874
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## ANOVA comparison for outer variable
stat.out <- dat.clean %>%
anova_test(conc ~ day) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges p.signif p.format
## 1 day 2 45 54.892 8.48e-13 * 0.709 **** <0.001
pwc2 <- dat.clean %>%
tukey_hsd(conc ~ day) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 3 × 10
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 day d08 d16 0 -9.71 -13.6 -5.86 6.42e- 7
## 2 day d08 d21 0 -16.0 -19.8 -12.1 1.55e-12
## 3 day d16 d21 0 -6.29 -10.7 -1.84 3.71e- 3
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "day", dodge = 0.8)
pwc2 <- pwc2 %>% add_xy_position(x = "day")
pwc2$y.position <- max(stat.in$y.position)*1.1
# Calculate slope and intercept for each group
reg_lines <- dat.clean %>%
group_by(feed) %>%
summarize(slope = coef(lm(conc ~ day))[2],
intercept = coef(lm(conc ~ day))[1])
# Statistical test of regression slopes from all d21 rats
rls <- dat.clean %>% subset(dissection == "d21") %>%
group_by(rat_name) %>%
summarize(slope = coef(lm(conc ~ day))[2],
intercept = coef(lm(conc ~ day))[1])
rls$group <- rep(c("LF","HF"), each = 6)
stat.rls <- rls %>%
t_test(slope ~ group,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.rls## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 -0.797 -8.36 -7.56 slope HF LF 6 6 -0.460 0.656
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
# Create ggboxplot with regression lines for feed types and slope values as text
p <- ggboxplot(dat.clean, x = "day", y = "conc",
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_color_manual(breaks = dat.clean$feed, values = c("LF" = "#222222","HF" = "#222222", "HF_PFOS" = "#004400","LF_PFOS" = "#000066")) +
scale_x_discrete(name = "Day", labels = c("Day 8","Day 16","Day 21")) +
guides(color = FALSE) +
theme(axis.title.x=element_blank()) +
geom_smooth(aes(group = feed, color = feedtreat), method = "lm", se = FALSE, size = 0.5, fullrange = TRUE, linetype = "dashed") +
annotate("text", x = 3, y = 65, label = paste("HF: ",round(reg_lines$slope[1],2)," µg/mL/day")) +
annotate("text", x = 3, y = 62, label = paste("LF: ",round(reg_lines$slope[2],2)," µg/mL/day"))
# Add statistics
p.stat <- p +
stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, label = "p.adj.signif", tip.length = 0, hide.ns = TRUE, y.position = c(73,76,70), limits = c(30,80),breaks = seq(30,80,10)) +
scale_y_continuous(name ="Serum PFOS ug / mL", expand = expansion(mult = c(0.01, 0.1)))
# View the final plot
p.stat## `geom_smooth()` using formula = 'y ~ x'
# Save plot as Rdata element
p.blood <- p.stat
save(p.blood, file = "plots/animal_data/pfos/systemic_blood_figure.Rdata")
# Save plots
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_blood_",OUTCOME,".png"), plot = p.stat, device = "png", units = "mm", dpi = 300, height = 100, width = 120))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_blood_",OUTCOME,".pdf"), plot = p.stat, device = "pdf", units = "mm", dpi = 300, height = 100, width = 120))
# Save output from ANOVA and post hoc
list.serum <- list(pwc = pwc,res.aov = res.aov)
for (i in names(list.serum)) {
write.csv(list.serum[[i]], file = paste0("plots/animal_data/pfos/serum_",i,"_results.csv"))
}
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())6.1.2 Brain tissue
6.1.2.1 ug/g
6.1.2.1.1 Prepare data
This section sets the variables to be used and prepares the data if necessary.
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Set names of variables
PREDICTOR <- "dissection"
OUTCOME <- "pfos_brain_ugg"
SUBJECT <- "rat_name"
# Subset to a specific varible
dat.clean <- subset(dat, treatment == "PFOS" & pfos_brain_ugg != "")
# Remove rows with NA
dat.clean <- subset(dat.clean, !is.na(pfos_brain_ugg))
# Will you run a paired test? (set variable to `TRUE` or `FALSE`)
PAIRED <- FALSE
# Create formula
FORMULA <- as.formula(paste(OUTCOME, PREDICTOR, sep = "~"))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(c("feed","dissection")))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("feed","dissection","n","min","max","mean","sd","se")## # A tibble: 4 × 8
## feed dissection n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF d08 5 3.90 5.08 4.39 0.429 0.192
## 2 HF d21 5 1.62 2.61 2.12 0.406 0.182
## 3 LF d08 5 3.06 4.66 3.92 0.596 0.267
## 4 LF d21 6 1.46 2.91 2.47 0.532 0.217
# Sort data for paired test
if (PAIRED) {
# Order data
dat.clean <- arrange(dat.clean, !!sym(SUBJECT))
# Remove unpaired samples
dat.clean <- dat.clean %>%
group_by(!!sym(SUBJECT)) %>%
filter(n() != 1) %>%
droplevels() %>%
ungroup()
}
# identify outliers
dat.clean %>%
group_by(!!sym(PREDICTOR)) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 2 × 79
## dissection rat_org rat_name cage treatment feed feedtreat feedtreatday
## <chr> <chr> <chr> <int> <chr> <chr> <chr> <chr>
## 1 d08 R18 R18 9 PFOS LF LF_PFOS LF_PFOS_d08
## 2 d08 R43 R41 22 PFOS HF HF_PFOS HF_PFOS_d08
## # ℹ 71 more variables: bw_minus18 <dbl>, bw_0 <dbl>, bw_1 <int>, bw_2 <int>,
## # bw_3 <int>, bw_4 <int>, bw_5 <int>, bw_6 <int>, bw_7 <int>, bw_8 <int>,
## # bw_12 <dbl>, bw_16 <dbl>, bw_21 <dbl>, bw_gain08 <dbl>, bw_gain021 <dbl>,
## # bw_gain821 <dbl>, bloodvol_8 <dbl>, bloodvol_16 <dbl>, bloodvol_21 <dbl>,
## # cecum_wt <dbl>, cecum_wtbw <dbl>, cecum_norm <dbl>, liver_wt <dbl>,
## # liver_wtbw <dbl>, liver_norm <dbl>, brain_wt_estimate <dbl>,
## # transit_0 <int>, transit_7 <int>, transit_20 <int>, dose_total_ml <dbl>, …
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 1 19 0.0112 0.917
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
No outliers were identified. Data is normally distributed and has equal variance. Hence we use t-test.
6.1.2.1.2 PERFORM TEST
T-test
We are now ready to perform the test
stat.test <- dat.clean %>%
t_test(FORMULA,
var.equal = EQUAL.VAR,
detailed = TRUE,
paired = FALSE,
alternative = "two.sided") %>%
add_significance()
stat.test## # A tibble: 1 × 16
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 1.84 4.16 2.31 pfos… d08 d21 10 11 8.13 1.31e-7
## # ℹ 6 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>
Effect size
The effect size is calculated as Cohen’s D
## # A tibble: 1 × 7
## .y. group1 group2 effsize n1 n2 magnitude
## * <chr> <chr> <chr> <dbl> <int> <int> <ord>
## 1 pfos_brain_ugg d08 d21 3.55 10 11 large
6.1.2.1.3 Nested analysis and Figure
# Set variables for inner and outer analyses
INNER.VAR <- "feed"
OUTER.VAR <- "dissection"
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(dissection) %>%
t_test(pfos_brain_ugg ~ feed,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## dissection estimate estimate1 estimate2 .y. group1 group2 n1 n2
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 d08 0.467 4.39 3.92 pfos_brain_… HF LF 5 5
## 2 d21 -0.352 2.12 2.47 pfos_brain_… HF LF 5 6
## # ℹ 9 more variables: statistic <dbl>, p <dbl>, df <dbl>, conf.low <dbl>,
## # conf.high <dbl>, method <chr>, alternative <chr>, p.signif <chr>,
## # p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
t_test(pfos_brain_ugg ~ dissection,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 1.84 4.16 2.31 pfos… d08 d21 10 11 8.13 1.31e-7
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "dissection", dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = "dissection")
stat.out$y.position <- max(stat.in$y.position)*1.1
# Calculate slope and intercept for each group
reg_lines <- dat.clean %>%
group_by(feed) %>%
summarize(slope = coef(lm(pfos_brain_ugg ~ dissection))[2],
intercept = coef(lm(pfos_brain_ugg ~ dissection))[1])
# Create ggboxplot with regression lines for feed types and slope values as text
p <- ggboxplot(dat.clean, x = "dissection", y = "pfos_brain_ugg",
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_color_manual(breaks = dat.clean$feed, values = c("LF" = "#222222","HF" = "#222222", "HF_PFOS" = "#004400","LF_PFOS" = "#000066")) +
scale_x_discrete(name = "Day", labels = c("Day 8","Day 21")) +
guides(color = FALSE) +
theme(axis.title.x=element_blank()) +
geom_smooth(aes(group = feed, color = feedtreat), method = "lm", se = FALSE, size = 0.5, fullrange = TRUE, linetype = "dashed")
# Add statistics
p.stat <- p +
stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, label = "p.signif", tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name ="Brain PFOS ug / g", expand = expansion(mult = c(0.01, 0.1)), limits = c(1,6), breaks = seq(1,6,1)) +
annotate("text", x = 2, y = 5.1, size = 3, label = paste0("HF: ",round(reg_lines$slope[1],2)," µg/g/day")) +
annotate("text", x = 2, y = 4.7, size = 3, label = paste0("LF: ",round(reg_lines$slope[2],2)," µg/g/day"))
# View the final plot
p.stat## `geom_smooth()` using formula = 'y ~ x'
# Save plot as Rdata element
p.brain <- p.stat
save(p.brain, file = "plots/animal_data/pfos/systemic_brain_figure.Rdata")
# Save plot as PNG and PDF formats
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_brain_",OUTCOME,".png"), plot = p.stat, device = "png", units = "mm", dpi = 300, height = 100, width = 90))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_brain_",OUTCOME,".pdf"), plot = p.stat, device = "pdf", units = "mm", dpi = 300, height = 100, width = 90))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())6.1.3 Liver tissue
6.1.3.1 ug/g
6.1.3.1.1 Prepare data
This section sets the variables to be used and prepares the data if necessary.
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Set names of variables
PREDICTOR <- "dissection"
OUTCOME <- "pfos_liver_ugg"
SUBJECT <- "rat_name"
# Subset to a specific varible
dat.clean <- subset(dat, treatment == "PFOS" & !is.na(pfos_liver_ugg))
# Will yoou run a paired test? (set variable to `TRUE` or `FALSE`)
PAIRED <- FALSE
# Create formula
FORMULA <- as.formula(paste(OUTCOME, PREDICTOR, sep = "~"))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(c("feed","dissection")))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("feed","dissection","n","min","max","mean","sd","se")## # A tibble: 4 × 8
## feed dissection n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF d08 6 185. 204. 194. 7.56 3.09
## 2 HF d21 6 138. 156. 147. 6.58 2.69
## 3 LF d08 6 156. 187. 170. 12.0 4.89
## 4 LF d21 6 136. 157. 145. 8.16 3.33
# Sort data for paired test
if (PAIRED) {
# Order data
dat.clean <- arrange(dat.clean, !!sym(SUBJECT))
# Remove unpaired samples
dat.clean <- dat.clean %>%
group_by(!!sym(SUBJECT)) %>%
filter(n() != 1) %>%
arrange(!!sym(PREDICTOR), !!sym(SUBJECT)) %>%
droplevels() %>%
ungroup()
}
# Summary samples in groups
dat.clean %>% group_by(across(all_of("feedtreatday"))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 4 × 5
## feedtreatday variable n mean sd
## <chr> <fct> <dbl> <dbl> <dbl>
## 1 HF_PFOS_d08 pfos_liver_ugg 6 194. 7.56
## 2 HF_PFOS_d21 pfos_liver_ugg 6 147. 6.58
## 3 LF_PFOS_d08 pfos_liver_ugg 6 170. 12.0
## 4 LF_PFOS_d21 pfos_liver_ugg 6 145. 8.16
## [1] dissection rat_org rat_name cage
## [5] treatment feed feedtreat feedtreatday
## [9] bw_minus18 bw_0 bw_1 bw_2
## [13] bw_3 bw_4 bw_5 bw_6
## [17] bw_7 bw_8 bw_12 bw_16
## [21] bw_21 bw_gain08 bw_gain021 bw_gain821
## [25] bloodvol_8 bloodvol_16 bloodvol_21 cecum_wt
## [29] cecum_wtbw cecum_norm liver_wt liver_wtbw
## [33] liver_norm brain_wt_estimate transit_0 transit_7
## [37] transit_20 dose_total_ml pfos_total_mg pfos_liver_ugg
## [41] pfos_liver_mg pfos_liver8_pct pfos_brain_ugg pfos_brain_uggbw
## [45] pfos_brain_ug pfos_brain_pct pfos_serum8_ugml pfos_serum8_mg
## [49] pfos_serum8_pct pfos_serum16_ugml pfos_serum16_mg pfos_serum16_pct
## [53] pfos_serum21_ugml pfos_serum21_mg pfos_serum21_pct pfos_feces8_ugg
## [57] pfos_feces12_ugg pfos_feces16_ugg pfos_feces21_ugg pfos_cecum_ugg
## [61] pfos_urine8_ugml pfos_urine16_ugml pfos_urine21_ugml pH_je_up
## [65] pH_je_down pH_ileum pH_cecum acetic
## [69] formic propanoic m2_propanoic butanoic
## [73] m3_butanoic pentanoic m4_pentanoic hexanoic
## [77] heptanoic is.outlier is.extreme
## <0 rækker> (eller 0-længde row.names)
## # A tibble: 2 × 4
## dissection variable statistic p
## <chr> <chr> <dbl> <dbl>
## 1 d08 pfos_liver_ugg 0.942 0.518
## 2 d21 pfos_liver_ugg 0.936 0.448
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 1 22 4.60 0.0434
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
No outliers were identified. Data is normally distributed and has equal variance. Hence we use t-test.
6.1.3.1.2 PERFORM TEST
T-test
We are now ready to perform the test
stat.test <- dat.clean %>%
t_test(FORMULA,
var.equal = EQUAL.VAR,
detailed = TRUE,
paired = FALSE,
alternative = "two.sided") %>%
add_significance()
stat.test## # A tibble: 1 × 16
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 36.4 182. 146. pfos… d08 d21 12 12 7.24 2.63e-6
## # ℹ 6 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>
Effect size
The effect size is calculated as Cohen’s D
## # A tibble: 1 × 7
## .y. group1 group2 effsize n1 n2 magnitude
## * <chr> <chr> <chr> <dbl> <int> <int> <ord>
## 1 pfos_liver_ugg d08 d21 2.96 12 12 large
6.1.3.1.3 Nested analysis and Figure
# Set variables for inner and outer analyses
INNER.VAR <- "feed"
OUTER.VAR <- "dissection"
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(dissection) %>%
t_test(pfos_liver_ugg ~ feed,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## dissection estimate estimate1 estimate2 .y. group1 group2 n1 n2
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 d08 24.3 194. 170. pfos_liver_… HF LF 6 6
## 2 d21 1.43 147. 145. pfos_liver_… HF LF 6 6
## # ℹ 9 more variables: statistic <dbl>, p <dbl>, df <dbl>, conf.low <dbl>,
## # conf.high <dbl>, method <chr>, alternative <chr>, p.signif <chr>,
## # p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
t_test(pfos_liver_ugg ~ dissection,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 36.4 182. 146. pfos… d08 d21 12 12 7.24 2.63e-6
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "dissection", dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = "dissection")
stat.out$y.position <- max(stat.in$y.position)*1.1
# Calculate slope and intercept for each group
reg_lines <- dat.clean %>%
group_by(feed) %>%
summarize(slope = coef(lm(pfos_liver_ugg ~ dissection))[2],
intercept = coef(lm(pfos_liver_ugg ~ dissection))[1])
# Create ggboxplot with regression lines for feed types and slope values as text
p <- ggboxplot(dat.clean, x = "dissection", y = "pfos_liver_ugg",
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_color_manual(breaks = dat.clean$feed, values = c("LF" = "#222222","HF" = "#222222", "HF_PFOS" = "#004400","LF_PFOS" = "#000066")) +
scale_x_discrete(name = "Day", labels = c("Day 8","Day 21")) +
guides(color = FALSE) +
theme(axis.title.x=element_blank()) +
geom_smooth(aes(group = feed, color = feedtreat), method = "lm", se = FALSE, size = 0.5, fullrange = TRUE, linetype = "dashed")
# Add statistics
p.stat <- p +
stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, label = "p.signif", tip.length = 0, hide.ns = TRUE, y.position = 225) +
scale_y_continuous(name ="Liver PFOS ug / g", expand = expansion(mult = c(0.01, 0.1)), limits = c(125,225), breaks = seq(125,225,25)) +
annotate("text", x = 2, y = 210, size = 3, label = paste0("HF: ",round(reg_lines$slope[1],2)," µg/g/day")) +
annotate("text", x = 2, y = 203, size = 3, label = paste0("LF: ",round(reg_lines$slope[2],2)," µg/g/day"))
# View the final plot
p.stat## `geom_smooth()` using formula = 'y ~ x'
# Save plot as Rdata element
p.liver <- p.stat
save(p.liver, file = "plots/animal_data/pfos/systemic_liverugg_figure.Rdata")
# Save plot as PNG and PDF formats
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_liver_",OUTCOME,".png"), plot = p.stat, device = "png", units = "mm", dpi = 300, height = 100, width = 90))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_liver_",OUTCOME,".pdf"), plot = p.stat, device = "pdf", units = "mm", dpi = 300, height = 100, width = 90))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())6.1.3.2 mg total liver weight
6.1.3.2.1 Prepare data
This section sets the variables to be used and prepares the data if necessary.
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Set names of variables
PREDICTOR <- "dissection"#c("feed","day")
OUTCOME <- "pfos_liver_mg"
SUBJECT <- "rat_name"
# Subset to a specific varible
dat.clean <- subset(dat, treatment == "PFOS")
# Remove rows with NA
dat.clean <- subset(dat.clean, !is.na(pfos_liver_mg))
# Will yoou run a paired test? (set variable to `TRUE` or `FALSE`)
PAIRED <- FALSE
# Create formula
FORMULA <- as.formula(paste(OUTCOME, PREDICTOR, sep = "~"))
# Sort data for paired test
if (PAIRED) {
# Order data
dat.clean <- arrange(dat.clean, !!sym(SUBJECT))
# Remove unpaired samples
dat.clean <- dat.clean %>%
group_by(!!sym(SUBJECT)) %>%
filter(n() != 1) %>%
arrange(!!sym(PREDICTOR), !!sym(SUBJECT)) %>%
droplevels() %>%
ungroup()
}
# Summary samples in groups
dat.clean %>% group_by(across(all_of("feedtreatday"))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 4 × 5
## feedtreatday variable n mean sd
## <chr> <fct> <dbl> <dbl> <dbl>
## 1 HF_PFOS_d08 pfos_liver_mg 6 3.25 0.333
## 2 HF_PFOS_d21 pfos_liver_mg 6 2.62 0.215
## 3 LF_PFOS_d08 pfos_liver_mg 6 3.15 0.554
## 4 LF_PFOS_d21 pfos_liver_mg 6 2.58 0.373
## [1] dissection rat_org rat_name cage
## [5] treatment feed feedtreat feedtreatday
## [9] bw_minus18 bw_0 bw_1 bw_2
## [13] bw_3 bw_4 bw_5 bw_6
## [17] bw_7 bw_8 bw_12 bw_16
## [21] bw_21 bw_gain08 bw_gain021 bw_gain821
## [25] bloodvol_8 bloodvol_16 bloodvol_21 cecum_wt
## [29] cecum_wtbw cecum_norm liver_wt liver_wtbw
## [33] liver_norm brain_wt_estimate transit_0 transit_7
## [37] transit_20 dose_total_ml pfos_total_mg pfos_liver_ugg
## [41] pfos_liver_mg pfos_liver8_pct pfos_brain_ugg pfos_brain_uggbw
## [45] pfos_brain_ug pfos_brain_pct pfos_serum8_ugml pfos_serum8_mg
## [49] pfos_serum8_pct pfos_serum16_ugml pfos_serum16_mg pfos_serum16_pct
## [53] pfos_serum21_ugml pfos_serum21_mg pfos_serum21_pct pfos_feces8_ugg
## [57] pfos_feces12_ugg pfos_feces16_ugg pfos_feces21_ugg pfos_cecum_ugg
## [61] pfos_urine8_ugml pfos_urine16_ugml pfos_urine21_ugml pH_je_up
## [65] pH_je_down pH_ileum pH_cecum acetic
## [69] formic propanoic m2_propanoic butanoic
## [73] m3_butanoic pentanoic m4_pentanoic hexanoic
## [77] heptanoic is.outlier is.extreme
## <0 rækker> (eller 0-længde row.names)
## # A tibble: 2 × 4
## dissection variable statistic p
## <chr> <chr> <dbl> <dbl>
## 1 d08 pfos_liver_mg 0.943 0.536
## 2 d21 pfos_liver_mg 0.942 0.529
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 1 22 3.58 0.0716
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
No outliers were identified. Data is normally distributed and has equal variance. Hence we use t-test.
6.1.3.2.2 PERFORM TEST
T-test
We are now ready to perform the test
stat.test <- dat.clean %>%
t_test(FORMULA,
var.equal = EQUAL.VAR,
detailed = TRUE,
paired = FALSE,
alternative = "two.sided") %>%
add_significance()
stat.test## # A tibble: 1 × 16
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 0.603 3.20 2.60 pfos… d08 d21 12 12 3.96 6.64e-4
## # ℹ 6 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>
Effect size
The effect size is calculated as Cohen’s D
## # A tibble: 1 × 7
## .y. group1 group2 effsize n1 n2 magnitude
## * <chr> <chr> <chr> <dbl> <int> <int> <ord>
## 1 pfos_liver_mg d08 d21 1.62 12 12 large
6.1.3.2.3 Nested analysis and Figure
# Set variables for inner and outer analyses
INNER.VAR <- "feed"
OUTER.VAR <- "dissection"
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(dissection) %>%
t_test(pfos_liver_mg ~ feed,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## dissection estimate estimate1 estimate2 .y. group1 group2 n1 n2
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 d08 0.105 3.25 3.15 pfos_liver_… HF LF 6 6
## 2 d21 0.0371 2.62 2.58 pfos_liver_… HF LF 6 6
## # ℹ 9 more variables: statistic <dbl>, p <dbl>, df <dbl>, conf.low <dbl>,
## # conf.high <dbl>, method <chr>, alternative <chr>, p.signif <chr>,
## # p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
t_test(pfos_liver_mg ~ dissection,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 0.603 3.20 2.60 pfos… d08 d21 12 12 3.96 6.64e-4
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "dissection", dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = "dissection")
stat.out$y.position <- max(stat.in$y.position)*1.1
# Calculate slope and intercept for each group
reg_lines <- dat.clean %>%
group_by(feed) %>%
summarize(slope = coef(lm(pfos_liver_mg ~ dissection))[2],
intercept = coef(lm(pfos_liver_mg ~ dissection))[1])
# Create ggboxplot with regression lines for feed types and slope values as text
p <- ggboxplot(dat.clean, x = "dissection", y = "pfos_liver_mg",
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_fill_manual(values = params$COLFEED, labels = c("HF","LF"), name = "Feed") +
scale_color_manual(breaks = dat.clean$feed, values = c("LF" = "#222222","HF" = "#222222", "HF_PFOS" = "#004400","LF_PFOS" = "#000066")) +
scale_x_discrete(name = "Day", labels = c("Day 8","Day 21")) +
guides(color = FALSE) +
theme(axis.title.x=element_blank()) +
geom_smooth(aes(group = feed, color = feedtreat), method = "lm", se = FALSE, size = 0.5, fullrange = TRUE, linetype = "dashed")
# Add statistics
p.stat <- p +
stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, label = "p.signif", tip.length = 0, hide.ns = TRUE, y.position = 4.1) +
scale_y_continuous(name ="Liver PFOS mg", expand = expansion(mult = c(0.01, 0.1)), limits = c(2,4.3), breaks = seq(2,4.2,0.5)) +
annotate("text", x = 2, y = 3.75, size = 3, label = paste0("HF: ",round(reg_lines$slope[1],2)," mg/day")) +
annotate("text", x = 2, y = 3.6, size = 3, label = paste0("LF: ",round(reg_lines$slope[2],2)," mg/day"))
# View the final plot
p.stat## `geom_smooth()` using formula = 'y ~ x'
# Save plot as Rdata element
p.livermg <- p.stat
save(p.livermg, file = "plots/animal_data/pfos/systemic_livermg_figure.Rdata")
# Save plot as PNG and PDF formats
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_liver_",OUTCOME,".png"), plot = p.stat, device = "png", units = "mm", dpi = 300, height = 100, width = 90))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_liver_",OUTCOME,".pdf"), plot = p.stat, device = "pdf", units = "mm", dpi = 300, height = 100, width = 90))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())6.1.4 Liver PFOS Accumulation
In this section we explore the large difference in HF-PFOS and LF-PFOS on Day 8 measured in ug/g. The hypothesis is that the increased relative liver weight in LF-PFOS in Day 8 plays a role in lowering the PFOS concentration per gram liver as daily PFOS dosing is dependent on body weight. In the available dataset there are already values available for liver weight at day of dissection (liver_wt), relative liver weight at day of dissection (liver_wtbw), total dose of PFOS given per rat dependent on body weight in mg (pfos_total_mg), and PFOS concentration in liver samples (per gram liver: pfos_liver_ugg, and for total liver weight: pfos_liver_mg)
6.1.4.1 mg
6.1.4.1.1 Prepare data and create figure
# Load data
load("R_objects/animal_data.Rdata")
dat.clean <- dat %>% subset(treatment == "PFOS") %>%
select("rat_name","dissection","treatment","feed","feedtreat","bw_8","bw_21","liver_wt","liver_wtbw","pfos_total_mg","pfos_liver_ugg","pfos_liver_mg")
for (rat in dat.clean$rat_name) {
dat.clean$pfos_liver_pct <- (dat.clean$pfos_liver_mg / dat.clean$pfos_total_mg)*100
}
# Set names of variables
PREDICTOR <- "dissection"#c("feed","day")
OUTCOME <- "pfos_liver_pct"
SUBJECT <- "rat_name"
# Will you run a paired test? (set variable to `TRUE` or `FALSE`)
PAIRED <- FALSE
# Create formula
FORMULA <- as.formula(paste(OUTCOME, PREDICTOR, sep = "~"))
# Sort data for paired test
if (PAIRED) {
# Order data
dat.clean <- arrange(dat.clean, !!sym(SUBJECT))
# Remove unpaired samples
dat.clean <- dat.clean %>%
group_by(!!sym(SUBJECT)) %>%
filter(n() != 1) %>%
arrange(!!sym(PREDICTOR), !!sym(SUBJECT)) %>%
droplevels() %>%
ungroup()
}
# identify outliers
dat.clean %>%
group_by(!!sym(PREDICTOR)) %>%
identify_outliers(!!sym(OUTCOME))## [1] dissection rat_name treatment feed feedtreat
## [6] bw_8 bw_21 liver_wt liver_wtbw pfos_total_mg
## [11] pfos_liver_ugg pfos_liver_mg pfos_liver_pct is.outlier is.extreme
## <0 rækker> (eller 0-længde row.names)
# Run Shapiro test (normality)
dat.clean %>%
group_by(!!sym(PREDICTOR)) %>%
shapiro_test(!!sym(OUTCOME))## # A tibble: 2 × 4
## dissection variable statistic p
## <chr> <chr> <dbl> <dbl>
## 1 d08 pfos_liver_pct 0.962 0.815
## 2 d21 pfos_liver_pct 0.976 0.961
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 1 22 1.03 0.320
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
# Set variables for inner and outer analyses
INNER.VAR <- "feed"
OUTER.VAR <- "dissection"
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(dissection) %>%
t_test(pfos_liver_pct ~ feed,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## dissection estimate estimate1 estimate2 .y. group1 group2 n1 n2
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 d08 2.76 48.8 46.0 pfos_liver_… HF LF 6 6
## 2 d21 0.182 40.0 39.8 pfos_liver_… HF LF 6 6
## # ℹ 9 more variables: statistic <dbl>, p <dbl>, df <dbl>, conf.low <dbl>,
## # conf.high <dbl>, method <chr>, alternative <chr>, p.signif <chr>,
## # p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
t_test(pfos_liver_pct ~ dissection,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 7.55 47.4 39.9 pfos… d08 d21 12 12 5.32 2.46e-5
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "dissection", dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = "dissection")
stat.out$y.position <- max(stat.in$y.position)*1.1
# Calculate slope and intercept for each group
reg_lines <- dat.clean %>%
group_by(feed) %>%
summarize(slope = coef(lm(pfos_liver_pct ~ dissection))[2],
intercept = coef(lm(pfos_liver_pct ~ dissection))[1])
# Create ggboxplot with regression lines for feed types and slope values as text
p <- ggboxplot(dat.clean, x = "dissection", y = "pfos_liver_pct",
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_fill_manual(values = params$COLFEED, labels = c("HF","LF"), name = "Feed") +
scale_color_manual(breaks = dat.clean$feed, values = c("LF" = "#222222","HF" = "#222222", "HF_PFOS" = "#004400","LF_PFOS" = "#000066")) +
scale_x_discrete(name = "Day", labels = c("Day 8","Day 21")) +
guides(color = FALSE) +
theme(axis.title.x=element_blank()) +
geom_smooth(aes(group = feed, color = feedtreat), method = "lm", se = FALSE, size = 0.5, fullrange = TRUE, linetype = "dashed")
# Add statistics
p.pct <- p +
stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, label = "p.signif", tip.length = 0, hide.ns = TRUE, y.position = 55) +
scale_y_continuous(name ="Total dosed PFOS in Liver (%)", expand = expansion(mult = c(0.01, 0.05)), labels = function(x) paste0(x, "%")) +
annotate("text", x = 2, y = 51, size = 3, label = paste0("HF: ",round(reg_lines$slope[1],2)," %/day")) +
annotate("text", x = 2, y = 50, size = 3, label = paste0("LF: ",round(reg_lines$slope[2],2)," %/day"))
p.pct## `geom_smooth()` using formula = 'y ~ x'
# Save plot as PNG and PDF formats
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_liver_",OUTCOME,".png"), plot = p.pct, device = "png", units = "mm", dpi = 300, height = 100, width = 90))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_liver_",OUTCOME,".pdf"), plot = p.pct, device = "pdf", units = "mm", dpi = 300, height = 100, width = 90))
#test liver_wtbw between HF-PFOS and LF-PFOS
hf <- dat.clean %>% subset(feed == "HF" & dissection == "d08")
lf <- dat.clean %>% subset(feed == "LF" & dissection == "d08")
lfhf_liver <- (mean(lf$liver_wtbw) / mean(hf$liver_wtbw))
print(paste0("Ratio between relative LF and HF liver weight: ",round(lfhf_liver,3)))## [1] "Ratio between relative LF and HF liver weight: 1.052"
lfhf_pfos <- (mean(lf$pfos_liver_ugg) / mean(hf$pfos_liver_ugg))
print(paste0("Ratio between LF and HF liver PFOS ug/g: ",round(lfhf_pfos,3)))## [1] "Ratio between LF and HF liver PFOS ug/g: 0.875"
# Setup and save Liver PFOS plots for final figure
load("plots/animal_data/pfos/systemic_liverugg_figure.Rdata")
load("plots/animal_data/pfos/systemic_livermg_figure.Rdata")
p.liver <- p.liver + theme(legend.position = "none")
p.pct <- p.pct + theme(legend.position = "none")
p1 <- ggarrange(p.liver,p.livermg,
nrow = 1, ncol = 2,
widths = c(1,1),
labels = c("B","C"))## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_liver_combined.png"), plot = p1, device = "png", units = "mm", dpi = 300, height = 100, width = 150))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/systemic_liver_combined.pdf"), plot = p1, device = "pdf", units = "mm", dpi = 300, height = 100, width = 150))
# Save plot as Rdata element
p.liverpct <- p.pct + theme(legend.position = "none")
p.livercomb <- p1 + theme(legend.position = "none")
save(p.livercomb, p.liverpct, file = "plots/animal_data/pfos/systemic_liver_figure.Rdata")6.1.4.1.2 Conclusion
No difference in total accumulated PFOS relative to total amount dosed was observed meaning that the observed difference in µg/g arise from difference in liver size relative to body size - this also reflects that the liver has an active uptake of PFOS which might me in equilibrium with blood concentration.
6.2 EXCRETED MEASUREMENTS
Following PFOS measurements from excreted samples are analysed and presented here:
- Feces from day 8, 12, 16, and 21
- Cecum from dissection days 8 and 21
- Urine from day 8, 16, and 21
6.2.1 Feces
6.2.1.1 ug/g
#####Prepare data
# Load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Set parameters
PREDICTOR <- c("feed","day")
OUTCOME <- "conc"
SUBJECT <- "rat_name"
# Create data frame for data representation
dat.clean <- dat %>% select(rat_name, feed, treatment, feedtreat, dissection, bw_8, bw_12, bw_16, bw_21, pfos_total_mg, pfos_feces8_ugg, pfos_feces12_ugg, pfos_feces16_ugg, pfos_feces21_ugg) %>%
pivot_longer(., cols = c(pfos_feces8_ugg, pfos_feces12_ugg, pfos_feces16_ugg, pfos_feces21_ugg), names_to = "pfos_day", values_to = "conc")
# Create column for day of sampling
dat.clean <- dat.clean %>%
mutate("day" = case_when(pfos_day == "pfos_feces8_ugg" ~ "d08",
pfos_day == "pfos_feces12_ugg" ~ "d12",
pfos_day == "pfos_feces16_ugg" ~ "d16",
pfos_day == "pfos_feces21_ugg" ~ "d21"))
# Order dataframe for analysis
dat.clean <- dat.clean[order(dat.clean$day),]
# Remove rows with NA
dat.clean <- subset(dat.clean, !is.na(conc))
# Subset to only PFOS groups
dat.clean <- subset(dat.clean, dat.clean$treatment == "PFOS")
dat.clean## # A tibble: 60 × 13
## rat_name feed treatment feedtreat dissection bw_8 bw_12 bw_16 bw_21
## <chr> <chr> <chr> <chr> <chr> <int> <dbl> <dbl> <dbl>
## 1 R13 LF PFOS LF_PFOS d08 373 NA NA NA
## 2 R14 LF PFOS LF_PFOS d08 390 NA NA NA
## 3 R15 LF PFOS LF_PFOS d08 341 NA NA NA
## 4 R16 LF PFOS LF_PFOS d08 299 NA NA NA
## 5 R17 LF PFOS LF_PFOS d08 322 NA NA NA
## 6 R18 LF PFOS LF_PFOS d08 423 NA NA NA
## 7 R19 LF PFOS LF_PFOS d21 344 361. 397. 403.
## 8 R20 LF PFOS LF_PFOS d21 357 383. 421. 442.
## 9 R21 LF PFOS LF_PFOS d21 342 366. 391. 422.
## 10 R22 LF PFOS LF_PFOS d21 349 382. 417. 432.
## # ℹ 50 more rows
## # ℹ 4 more variables: pfos_total_mg <dbl>, pfos_day <chr>, conc <dbl>,
## # day <chr>
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("feed","day","n","min","max","mean","sd","se")## # A tibble: 8 × 8
## feed day n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF d08 12 2.21 4.65 3.49 0.777 0.224
## 2 HF d12 6 1.89 3.06 2.49 0.393 0.16
## 3 HF d16 6 1.63 2.68 2.22 0.426 0.174
## 4 HF d21 6 1.32 2.75 2.06 0.612 0.25
## 5 LF d08 12 1.09 2.18 1.61 0.292 0.084
## 6 LF d12 6 0.864 1.74 1.34 0.349 0.142
## 7 LF d16 6 1.10 1.86 1.42 0.322 0.132
## 8 LF d21 6 0.877 1.23 1.06 0.129 0.053
# Create plot
bxp <- dat.clean %>%
ggboxplot(x = if_else(length(PREDICTOR) > 1, PREDICTOR[2],PREDICTOR[1]),
y = OUTCOME,
color = PREDICTOR[1],
facet.by = if(length(PREDICTOR) == 3) PREDICTOR[3],
palette = "jco")
bxp# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## [1] feed day rat_name treatment feedtreat
## [6] dissection bw_8 bw_12 bw_16 bw_21
## [11] pfos_total_mg pfos_day conc is.outlier is.extreme
## <0 rækker> (eller 0-længde row.names)
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.980 0.422
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 7 52 2.74 0.0170
This all shows that normalised cecum weight data has two outliers, is normally distribution and has equal variance. Therefore we use a Welch ANOVA test with Games Howell posthoc test to test data for all factors of interest, while using unpaired t-test for pairwise comparisons.
6.2.1.1.1 WELCH’s ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## # A tibble: 1 × 7
## .y. n statistic DFn DFd p method
## * <chr> <int> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 conc 60 24.8 7 19.3 0.0000000236 Welch ANOVA
ANOVA shows that day and feed have significant effects on the overall data.
Perform posthoc test
A significant one-way ANOVA is generally followed up by Tukey post-hoc tests to perform multiple pairwise comparisons between groups. When running relaxed Welch one-way test, the Games-Howell post hoc test or pairwise t-tests (with no assumption of equal variances) can be used to compare all possible combinations of group differences.
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
PREDICTOR2 <- "day"
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR2, sep = " ~ "))
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 6 × 8
## .y. group1 group2 estimate conf.low conf.high p.adj p.adj.signif
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 conc d08 d12 -0.632 -1.46 0.191 0.181 ns
## 2 conc d08 d16 -0.728 -1.48 0.0246 0.061 ns
## 3 conc d08 d21 -0.987 -1.80 -0.176 0.012 *
## 4 conc d12 d16 -0.0957 -0.811 0.620 0.982 ns
## 5 conc d12 d21 -0.355 -1.13 0.421 0.59 ns
## 6 conc d16 d21 -0.259 -0.960 0.441 0.734 ns
Posthoc analysis however show significant differences between to be between overall treatment, overall dissection days, as well as cross-day comparisons.
6.2.1.1.2 Nested analysis and Figure
# Set variables for inner and outer analyses
INNER.VAR <- "feed"
OUTER.VAR <- "day"
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(day) %>%
t_test(conc ~ feed,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 4 × 18
## day estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 d08 1.88 3.49 1.61 conc HF LF 12 12 7.84
## 2 d12 1.15 2.49 1.34 conc HF LF 6 6 5.34
## 3 d16 0.806 2.23 1.42 conc HF LF 6 6 3.69
## 4 d21 1.00 2.07 1.06 conc HF LF 6 6 3.93
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
welch_anova_test(conc ~ day) %>%
# dunn_test(conc ~ day, p.adjust.method = "fdr") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 9
## .y. n statistic DFn DFd p method p.signif p.format
## * <chr> <int> <dbl> <dbl> <dbl> <dbl> <chr> <chr> <chr>
## 1 conc 60 3.62 3 28.8 0.025 Welch ANOVA * 0.025
pwc2 <- dat.clean %>%
# kruskal_test(conc ~ day) %>%
games_howell_test(conc ~ day) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 6 × 9
## .y. group1 group2 estimate conf.low conf.high p.adj p.adj.signif
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 conc d08 d12 -0.632 -1.46 0.191 0.181 ns
## 2 conc d08 d16 -0.728 -1.48 0.0246 0.061 ns
## 3 conc d08 d21 -0.987 -1.80 -0.176 0.012 *
## 4 conc d12 d16 -0.0957 -0.811 0.620 0.982 ns
## 5 conc d12 d21 -0.355 -1.13 0.421 0.59 ns
## 6 conc d16 d21 -0.259 -0.960 0.441 0.734 ns
## # ℹ 1 more variable: p.adj.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "day", dodge = 0.8)
pwc2 <- pwc2 %>% add_xy_position(x = "day")
pwc2$y.position <- max(stat.in$y.position)*1.1
# Calculate slope and intercept for each group
reg_lines <- dat.clean %>%
group_by(feed) %>%
summarize(slope = coef(lm(conc ~ day))[2],
intercept = coef(lm(conc ~ day))[1])
# Statistical test of regression slopes from all d21 rats
rls <- dat.clean %>% subset(dissection == "d21") %>%
group_by(rat_name) %>%
summarize(slope = coef(lm(conc ~ day))[2],
intercept = coef(lm(conc ~ day))[1])
rls$group <- rep(c("LF","HF"), each = 6)
stat.rls <- rls %>%
t_test(slope ~ group,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.rls## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 -0.561 -0.770 -0.209 slope HF LF 6 6 -1.68 0.126
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
# Create ggboxplot with regression lines for feed types and slope values as text
p <- ggboxplot(dat.clean, x = "day", y = "conc",
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_color_manual(breaks = dat.clean$feed, values = c("LF" = "#222222","HF" = "#222222")) +
scale_x_discrete(name = "Day", labels = c("Day 8","Day 12","Day 16","Day 21")) +
guides(color = FALSE) +
theme(axis.title.x=element_blank())
# Add statistics
p.stat <- p +
stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, label = "p.adj.signif", tip.length = 0, hide.ns = TRUE) +#, y.position = c(5.4,5.7,6,4.8,5.1,4.5))+#, limits = c(30,80),breaks = seq(30,80,10)) +
scale_y_continuous(name ="Faeces PFOS ug / g", expand = expansion(mult = c(0.01, 0.1)))
# View the final plot
p.stat# Save plot as Rdata element
p.faeces <- p.stat
save(p.faeces, file = "plots/animal_data/pfos/systemic_faeces_figure.Rdata")
# Save plots
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/excreted_feces_",OUTCOME,".png"), plot = p.stat, device = "png", units = "mm", dpi = 300, height = 100, width = 150))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/excreted_feces_",OUTCOME,".pdf"), plot = p.stat, device = "pdf", units = "mm", dpi = 300, height = 100, width = 150))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())6.2.2 Cecum
6.2.2.1 ug/g
6.2.2.1.1 Prepare data
This section sets the variables to be used and prepares the data if necessary.
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Set names of variables
PREDICTOR <- "dissection"#c("feed","dissection")
OUTCOME <- "pfos_cecum_ugg"
SUBJECT <- "rat_name"
# Subset to a specific varible
dat.clean <- subset(dat, treatment == "PFOS")
# Remove rows with NA
dat.clean <- subset(dat.clean, !is.na(pfos_cecum_ugg))
# Will you run a paired test? (set variable to `TRUE` or `FALSE`)
PAIRED <- FALSE
# Create formula
FORMULA <- as.formula(paste(OUTCOME, PREDICTOR, sep = "~"))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(c("feed","dissection")))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("feed","dissection","n","min","max","mean","sd","se")## # A tibble: 4 × 8
## feed dissection n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF d08 6 0.919 1.88 1.51 0.346 0.141
## 2 HF d21 6 1.06 1.22 1.14 0.06 0.024
## 3 LF d08 6 0.765 1.02 0.907 0.093 0.038
## 4 LF d21 6 0.526 0.881 0.742 0.153 0.062
# Sort data for paired test
if (PAIRED) {
# Order data
dat.clean <- arrange(dat.clean, !!sym(SUBJECT))
# Remove unpaired samples
dat.clean <- dat.clean %>%
group_by(!!sym(SUBJECT)) %>%
filter(n() != 1) %>%
arrange(!!sym(PREDICTOR), !!sym(SUBJECT)) %>%
droplevels() %>%
ungroup()
}
# identify outliers
dat.clean %>%
group_by(!!sym(PREDICTOR)) %>%
identify_outliers(!!sym(OUTCOME))## [1] dissection rat_org rat_name cage
## [5] treatment feed feedtreat feedtreatday
## [9] bw_minus18 bw_0 bw_1 bw_2
## [13] bw_3 bw_4 bw_5 bw_6
## [17] bw_7 bw_8 bw_12 bw_16
## [21] bw_21 bw_gain08 bw_gain021 bw_gain821
## [25] bloodvol_8 bloodvol_16 bloodvol_21 cecum_wt
## [29] cecum_wtbw cecum_norm liver_wt liver_wtbw
## [33] liver_norm brain_wt_estimate transit_0 transit_7
## [37] transit_20 dose_total_ml pfos_total_mg pfos_liver_ugg
## [41] pfos_liver_mg pfos_liver8_pct pfos_brain_ugg pfos_brain_uggbw
## [45] pfos_brain_ug pfos_brain_pct pfos_serum8_ugml pfos_serum8_mg
## [49] pfos_serum8_pct pfos_serum16_ugml pfos_serum16_mg pfos_serum16_pct
## [53] pfos_serum21_ugml pfos_serum21_mg pfos_serum21_pct pfos_feces8_ugg
## [57] pfos_feces12_ugg pfos_feces16_ugg pfos_feces21_ugg pfos_cecum_ugg
## [61] pfos_urine8_ugml pfos_urine16_ugml pfos_urine21_ugml pH_je_up
## [65] pH_je_down pH_ileum pH_cecum acetic
## [69] formic propanoic m2_propanoic butanoic
## [73] m3_butanoic pentanoic m4_pentanoic hexanoic
## [77] heptanoic is.outlier is.extreme
## <0 rækker> (eller 0-længde row.names)
## # A tibble: 2 × 4
## dissection variable statistic p
## <chr> <chr> <dbl> <dbl>
## 1 d08 pfos_cecum_ugg 0.865 0.0563
## 2 d21 pfos_cecum_ugg 0.915 0.250
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 1 22 1.63 0.214
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
No outliers were identified. Data is normally distributed and has equal variance. Hence we use t-test.
6.2.2.1.2 PERFORM TEST
T-test
We are now ready to perform the test
stat.test <- dat.clean %>%
t_test(FORMULA,
var.equal = EQUAL.VAR,
detailed = TRUE,
paired = FALSE,
alternative = "two.sided") %>%
add_significance()
stat.test## # A tibble: 1 × 16
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 0.268 1.21 0.941 pfos_… d08 d21 12 12 2.01 0.0569
## # ℹ 6 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>
Effect size
The effect size is calculated as Cohen’s D
## # A tibble: 1 × 7
## .y. group1 group2 effsize n1 n2 magnitude
## * <chr> <chr> <chr> <dbl> <int> <int> <ord>
## 1 pfos_cecum_ugg d08 d21 0.821 12 12 large
6.2.2.1.3 Nested analysis and Figure
# Set variables for inner and outer analyses
INNER.VAR <- "feed"
OUTER.VAR <- "dissection"
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(dissection) %>%
t_test(pfos_cecum_ugg ~ feed,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## dissection estimate estimate1 estimate2 .y. group1 group2 n1 n2
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int>
## 1 d08 0.602 1.51 0.907 pfos_cecum_… HF LF 6 6
## 2 d21 0.397 1.14 0.742 pfos_cecum_… HF LF 6 6
## # ℹ 9 more variables: statistic <dbl>, p <dbl>, df <dbl>, conf.low <dbl>,
## # conf.high <dbl>, method <chr>, alternative <chr>, p.signif <chr>,
## # p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
t_test(pfos_cecum_ugg ~ dissection,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 0.268 1.21 0.941 pfos_… d08 d21 12 12 2.01 0.0569
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "dissection", dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = "dissection")
stat.out$y.position <- max(stat.in$y.position)*1.1
# Calculate slope and intercept for each group
reg_lines <- dat.clean %>%
group_by(feed) %>%
summarize(slope = coef(lm(pfos_cecum_ugg ~ dissection))[2],
intercept = coef(lm(pfos_cecum_ugg ~ dissection))[1])
# Create ggboxplot with regression lines for feed types and slope values as text
p <- ggboxplot(dat.clean, x = "dissection", y = "pfos_cecum_ugg",
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_fill_manual(values = params$COLFEED, name = "Feed") + #labels = c("High fibre","Low fibre")
scale_color_manual(breaks = dat.clean$feed, values = c("LF" = "#222222","HF" = "#222222")) +
scale_x_discrete(name = "Day", labels = c("Day 8","Day 21")) +
guides(color = FALSE) +
theme(axis.title.x=element_blank()) #+
# geom_smooth(aes(group = feed, color = feed), method = "lm", se = FALSE, size = 0.5, fullrange = TRUE, linetype = "dashed")
# Add statistics
p.stat <- p +
stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, label = "p.signif", tip.length = 0, hide.ns = TRUE, y.position = 2.2) +
scale_y_continuous(name ="Caecal content PFOS µg / g", expand = expansion(mult = c(0.01, 0.1)), limits = c(0.5,2.3), breaks = seq(0.5,2.3,0.5)) #+
# View the final plot
p.stat# Save plot as Rdata element
p.caecum <- p.stat
save(p.caecum, file = "plots/animal_data/pfos/systemic_caecum_figure.Rdata")
# Save plot as PNG and PDF formats
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/excreted_cecum_",OUTCOME,".png"), plot = p.stat, device = "png", units = "mm", dpi = 300, height = 100, width = 90))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/excreted_cecum_",OUTCOME,".pdf"), plot = p.stat, device = "pdf", units = "mm", dpi = 300, height = 100, width = 90))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())6.2.3 Urine
6.2.3.1 ug/mL
#####Prepare data
# Load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Set parameters
PREDICTOR <- "day"#c("day","feed")
OUTCOME <- "conc"
SUBJECT <- "rat_name"
# Create data frame for data representation
dat.clean <- dat %>% select(rat_name, feed, treatment, feedtreat, dissection, bw_8, bw_21, pfos_total_mg, pfos_urine8_ugml, pfos_urine16_ugml, pfos_urine21_ugml) %>%
pivot_longer(., cols = c(pfos_urine8_ugml, pfos_urine16_ugml, pfos_urine21_ugml), names_to = "pfos_day", values_to = "conc")
# Create column for day of sampling
dat.clean <- dat.clean %>%
mutate("day" = case_when(pfos_day == "pfos_urine8_ugml" ~ "d08",
pfos_day == "pfos_urine16_ugml" ~ "d16",
pfos_day == "pfos_urine21_ugml" ~ "d21"))
# Order dataframe for analysis
dat.clean <- dat.clean[order(dat.clean$day),]
# Remove rows with NA
dat.clean <- subset(dat.clean, !is.na(conc))
# Subset to only PFOS groups
dat.clean <- subset(dat.clean, dat.clean$treatment == "PFOS")
# Subset extreme outliers
dat.clean <- subset(dat.clean, !dat.clean$rat_name %in% c("R24","R46"))
dat.clean## # A tibble: 41 × 11
## rat_name feed treatment feedtreat dissection bw_8 bw_21 pfos_total_mg
## <chr> <chr> <chr> <chr> <chr> <int> <dbl> <dbl>
## 1 R13 LF PFOS LF_PFOS d08 373 NA 7.12
## 2 R14 LF PFOS LF_PFOS d08 390 NA 7.48
## 3 R15 LF PFOS LF_PFOS d08 341 NA 6.46
## 4 R16 LF PFOS LF_PFOS d08 299 NA 5.72
## 5 R17 LF PFOS LF_PFOS d08 322 NA 6.22
## 6 R18 LF PFOS LF_PFOS d08 423 NA 7.90
## 7 R20 LF PFOS LF_PFOS d21 357 442. 6.74
## 8 R21 LF PFOS LF_PFOS d21 342 422. 6.48
## 9 R22 LF PFOS LF_PFOS d21 349 432. 6.80
## 10 R23 LF PFOS LF_PFOS d21 337 442. 6.44
## # ℹ 31 more rows
## # ℹ 3 more variables: pfos_day <chr>, conc <dbl>, day <chr>
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(c("feed","day")))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("feed","day","n","min","max","mean","sd","se")## # A tibble: 6 × 8
## feed day n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF d08 11 0.33 1.19 0.58 0.234 0.07
## 2 HF d16 5 0.635 1.25 0.966 0.276 0.124
## 3 HF d21 5 0.107 0.584 0.247 0.196 0.088
## 4 LF d08 10 0.249 0.931 0.667 0.206 0.065
## 5 LF d16 5 0.323 2.24 1.23 0.731 0.327
## 6 LF d21 5 0.119 0.406 0.256 0.124 0.055
# Create plot
bxp <- dat.clean %>%
ggboxplot(x = if_else(length(PREDICTOR) > 1, PREDICTOR[2],PREDICTOR[1]),
y = OUTCOME,
color = PREDICTOR[1],
facet.by = if(length(PREDICTOR) == 3) PREDICTOR[3],
palette = "jco")
bxp# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 1 × 13
## day rat_name feed treatment feedtreat dissection bw_8 bw_21 pfos_total_mg
## <chr> <chr> <chr> <chr> <chr> <chr> <int> <dbl> <dbl>
## 1 d16 R19 LF PFOS LF_PFOS d21 344 403. 6.57
## # ℹ 4 more variables: pfos_day <chr>, conc <dbl>, is.outlier <lgl>,
## # is.extreme <lgl>
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.912 0.00393
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 2 38 4.25 0.0215
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
Urine PFOS concentrations has five outliers, no normal distribution and has equal variance. This all shows that normalised cecum weight data has two outliers, is normally distribution and has equal variance. Therefore we use a non-parametric Kruskal-Wallis test with Dunn’s p-value adjustment.
6.2.3.1.1 Kruskal-Wallis test
Perform test
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 conc 41 21.8 2 0.0000189 Kruskal-Wallis
Effect size
The eta squared, based on the H-statistic, can be used as the measure of the Kruskal-Wallis test effect size. The interpretation values commonly in published literature are: 0.01- < 0.06 (small effect), 0.06 - < 0.14 (moderate effect) and >= 0.14 (large effect).
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 conc 41 0.520 eta2[H] large
Post-hoc test if interaction is significant
A significant Kruskal-Wallis test is generally followed up by Dunn’s test to identify which groups are different. It’s also possible to use the Wilcoxon’s test to calculate pairwise comparisons between group levels with corrections for multiple testing.
## # A tibble: 3 × 9
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 conc d08 d16 21 10 2.11 0.0348 0.0348 *
## 2 conc d08 d21 21 10 -3.26 0.00113 0.00170 **
## 3 conc d16 d21 10 10 -4.61 0.00000402 0.0000120 ****
Posthoc analysis however show significant differences between to be between overall treatment, overall dissection days, as well as cross-day comparisons.
6.2.3.1.2 Nested analysis and Figure
# Set variables for inner and outer analyses
INNER.VAR <- "feed"
OUTER.VAR <- "day"
# Statistics costumed for facet plotting
## Pairwise comparison for inner variable
stat.in <- dat.clean %>%
group_by(.data[[OUTER.VAR]]) %>%
wilcox_test(as.formula(paste("conc ~", INNER.VAR, sep = " "))) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj") %>%
add_xy_position(x = OUTER.VAR, dodge = 0.8) %>%
p_format("p.adj", accuracy = 0.0001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 3 × 16
## day .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 d08 conc HF LF 11 10 33 0.132 0.396 ns
## 2 d16 conc HF LF 5 5 10 0.69 0.69 ns
## 3 d21 conc HF LF 5 5 9 0.548 0.69 ns
## # ℹ 6 more variables: y.position <dbl>, groups <named list>, x <dbl>,
## # xmin <dbl>, xmax <dbl>, p.adj.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
kruskal_test(conc ~ day) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 8
## .y. n statistic df p method p.signif p.format
## * <chr> <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 conc 41 21.8 2 0.0000189 Kruskal-Wallis **** <0.001
pwc2 <- dat.clean %>%
dunn_test(conc ~ day, p.adjust.method = "fdr") %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 3 × 10
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 conc d08 d16 21 10 2.11 0.0348 0.0348 *
## 2 conc d08 d21 21 10 -3.26 0.00113 0.00170 **
## 3 conc d16 d21 10 10 -4.61 0.00000402 0.0000120 ****
## # ℹ 1 more variable: p.adj.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "day", dodge = 0.8)
pwc2 <- pwc2 %>% add_xy_position(x = "day")
pwc2$y.position <- max(stat.in$y.position)*1.1
# Create ggboxplot with regression lines for feed types and slope values as text
p <- ggboxplot(dat.clean, x = "day", y = "conc",
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_color_manual(breaks = dat.clean$feed, values = c("LF" = "#222222","HF" = "#222222")) +
scale_x_discrete(name = "Day", labels = c("Day 8","Day 16","Day 21")) +
guides(color = FALSE) +
theme(axis.title.x=element_blank())
# Add statistics
p.stat <- p +
stat_pvalue_manual(stat.in, label = "p.adj.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, label = "p.adj.signif", tip.length = 0, hide.ns = TRUE, y.position = c(3.0,3.2,2.8), limits = c(0,3.2),breaks = seq(0,3.2,1)) +
scale_y_continuous(name ="Urine PFOS ug / mL", expand = expansion(mult = c(0.01, 0.1)))
# View the final plot
p.stat# Save plot as Rdata element
p.urine <- p.stat
save(p.urine, file = "plots/animal_data/pfos/systemic_urine_figure.Rdata")
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/excreted_urine_",OUTCOME,".png"), plot = p.stat, device = "png", units = "mm", dpi = 300, height = 100, width = 120))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/excreted_urine_",OUTCOME,".pdf"), plot = p.stat, device = "pdf", units = "mm", dpi = 300, height = 100, width = 120))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())6.3 FIGURE 4 - PFOS concentrations
6.3.1 Create figure
# Load plots
path <- "plots/animal_data/pfos/"
files <- as.list(dir(path = path, pattern = "*figure.Rdata"))
files <- lapply(files, function(x) paste0(path,x))
for (i in files) {
load(i)
}
# Create combined plot
legend <- get_legend(p.blood)## `geom_smooth()` using formula = 'y ~ x'
p1 <- ggarrange(p.brain, p.liver,p.livermg, p.blood,
nrow = 1, ncol = 4,
widths = c(2,2,2,3),
align = "v",
labels = c("A","B","C","D"),
font.label = list(size = 24, face = "bold"),
legend = FALSE,
hjust = 0)## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
p2 <- ggarrange(p.caecum, p.faeces, p.urine,
nrow = 1, ncol = 3,
widths = c(2,4,3),
align = "v",
labels = c("E","F","G"),
font.label = list(size = 24, face = "bold"),
legend = FALSE,
hjust = 0)
p2## Warning: Graphs cannot be vertically aligned unless the axis parameter is set.
## Placing graphs unaligned.
## Warning: Graphs cannot be horizontally aligned unless the axis parameter is
## set. Placing graphs unaligned.
suppressMessages(ggsave(filename = paste0("plots/figures/Figure 4 - total_pfos_conc_figure_v5.png"), plot = p3, device = "png", units = "mm", dpi = 300, height = 180, width = 350))
suppressMessages(ggsave(filename = paste0("plots/figures/Figure 4 - total_pfos_conc_figure_v5.pdf"), plot = p3, device = "pdf", units = "mm", dpi = 300, height = 180, width = 350))Final figure is polished in vector editing software.
7 PFOS ISOMER ANALYSIS
In this section we investigate branched (br-PFOS) and linear PFOS (l-PFOS) expressed as percentage of br-PFOS in the sample (br-PFOS %) based on calculated AMT. These data are obtained from quantitative mass spectrometry analysis on retention-time peaks for br-PFOS and l-PFOS, respectively.
Factors that will be investigated are each sample type (material: “Serum”, “Liver”, “Brain”, “Feces”, “Cecum”, “Urine”), day of sampling (differs between sample type but generally, day: “d08”, “d12”, “d16”, “d21”), feeding groups (feed: “LF”,“HF”) and level of br-PFOS % between samples and compound controls (“posctrl”).
7.1 Import data
Data is imported from CSV format. br-PFOS % were calculated by [br-PFOS] / [total PFOS] * 100.
# Load analysis data
dat <- read.csv("input/pfos_isomer_data.csv", header = TRUE, sep = ";", dec = ",")
#Add additional metadata + calculate br_pct (br-PFOS percentage)
for (i in dat$id) {
# Add columns for easier sorting of data downstream
dat$dayfeed <- paste0(dat$day,"_",dat$feed)
dat$matfeed <- paste0(dat$material,"_",dat$feed)
# Calculate br-PFOS % from quantitative AMT data of br-PFOS and total PFOS
dat$br_pct <- dat$pfos_b_amt / dat$pfos_t_amt
dat$l_pct <- 1 - dat$br_pct
}
dat## id sample_name rat_name sample_org rat_org type feed material
## 1 13 R13Sd08 R13 R13S8 R13 sample LF Serum
## 2 14 R14Sd08 R14 R14S8 R14 sample LF Serum
## 3 15 R15Sd08 R15 R15S8 R15 sample LF Serum
## 4 16 R16Sd08 R16 R16S8 R16 sample LF Serum
## 5 17 R17Sd08 R17 R17S8 R17 sample LF Serum
## 6 18 R18Sd08 R18 R18S8 R18 sample LF Serum
## 7 19 R19Sd08 R19 R19S8 R19 sample LF Serum
## 8 20 R20Sd08 R20 R20S8 R20 sample LF Serum
## 9 21 R21Sd08 R21 R21S8 R21 sample LF Serum
## 10 22 R22Sd08 R22 R22S8 R22 sample LF Serum
## 11 23 R23Sd08 R23 R23S8 R23 sample LF Serum
## 12 24 R24Sd08 R24 R24S8 R24 sample LF Serum
## 13 37 R37Sd08 R37 R37S8 R37 sample HF Serum
## 14 38 R38Sd08 R38 R38S8 R38 sample HF Serum
## 15 39 R39Sd08 R39 R39S8 R39 sample HF Serum
## 16 40 R40Sd08 R40 R40S8 R40 sample HF Serum
## 17 41 R43Sd08 R43 R41S8 R41 sample HF Serum
## 18 42 R44Sd08 R44 R42S8 R42 sample HF Serum
## 19 43 R41Sd08 R41 R43S8 R43 sample HF Serum
## 20 44 R42Sd08 R42 R44S8 R44 sample HF Serum
## 21 45 R45Sd08 R45 R45S8 R45 sample HF Serum
## 22 46 R46Sd08 R46 R46S8 R46 sample HF Serum
## 23 47 R47Sd08 R47 R47S8 R47 sample HF Serum
## 24 48 R48Sd08 R48 R48S8 R48 sample HF Serum
## 25 56 R20Sd16 R20 R20S16 R20 sample LF Serum
## 26 57 R21Sd16 R21 R21S16 R21 sample LF Serum
## 27 58 R22Sd16 R22 R22S16 R22 sample LF Serum
## 28 59 R23Sd16 R23 R23S16 R23 sample LF Serum
## 29 60 R24Sd16 R24 R24S16 R24 sample LF Serum
## 30 67 R43Sd16 R43 R41S16 R41 sample HF Serum
## 31 68 R44Sd16 R44 R42S16 R42 sample HF Serum
## 32 69 R45Sd16 R45 R45S16 R45 sample HF Serum
## 33 70 R46Sd16 R46 R46S16 R46 sample HF Serum
## 34 71 R47Sd16 R47 R47S16 R47 sample HF Serum
## 35 72 R48Sd16 R48 R48S16 R48 sample HF Serum
## 36 79 R19Sd21 R19 R19S21 R19 sample LF Serum
## 37 80 R20Sd21 R20 R20S21 R20 sample LF Serum
## 38 81 R21Sd21 R21 R21S21 R21 sample LF Serum
## 39 82 R22Sd21 R22 R22S21 R22 sample LF Serum
## 40 83 R23Sd21 R23 R23S21 R23 sample LF Serum
## 41 84 R24Sd21 R24 R24S21 R24 sample LF Serum
## 42 91 R43Sd21 R43 R41S21 R41 sample HF Serum
## 43 92 R44Sd21 R44 R42S21 R42 sample HF Serum
## 44 93 R45Sd21 R45 R45S21 R45 sample HF Serum
## 45 94 R46Sd21 R46 R46S21 R46 sample HF Serum
## 46 95 R47Sd21 R47 R47S21 R47 sample HF Serum
## 47 96 R48Sd21 R48 R48S21 R48 sample HF Serum
## 48 111 R17Bd08 R17 R17B8 R17 sample LF Brain
## 49 112 R18Bd08 R18 R18B8 R18 sample LF Brain
## 50 113 R19Bd21 R19 R19B21 R19 sample LF Brain
## 51 114 R20Bd21 R20 R20B21 R20 sample LF Brain
## 52 115 R21Bd21 R21 R21B21 R21 sample LF Brain
## 53 116 R22Bd21 R22 R22B21 R22 sample LF Brain
## 54 117 R23Bd21 R23 R23B21 R23 sample LF Brain
## 55 118 R24Bd21 R24 R24B21 R24 sample LF Brain
## 56 132 R38Bd08 R38 R38B8 R38 sample HF Brain
## 57 133 R39Bd08 R39 R39B8 R39 sample HF Brain
## 58 136 R44Bd21 R44 R42B21 R42 sample HF Brain
## 59 137 R41Bd08 R41 R43B8 R43 sample HF Brain
## 60 138 R42Bd08 R42 R44B8 R44 sample HF Brain
## 61 139 R45Bd21 R45 R45B21 R45 sample HF Brain
## 62 140 R46Bd21 R46 R46B21 R46 sample HF Brain
## 63 141 R47Bd21 R47 R47B21 R47 sample HF Brain
## 64 142 R48Bd21 R48 R48B21 R48 sample HF Brain
## 65 156 R13Ld08 R13 R13L8 R13 sample LF Liver
## 66 157 R14Ld08 R14 R14L8 R14 sample LF Liver
## 67 158 R15Ld08 R15 R15L8 R15 sample LF Liver
## 68 159 R16Ld08 R16 R16L8 R16 sample LF Liver
## 69 160 R17Ld08 R17 R17L8 R17 sample LF Liver
## 70 161 R18Ld08 R18 R18L8 R18 sample LF Liver
## 71 162 R19Ld21 R19 R19L21 R19 sample LF Liver
## 72 163 R20Ld21 R20 R20L21 R20 sample LF Liver
## 73 164 R21Ld21 R21 R21L21 R21 sample LF Liver
## 74 165 R22Ld21 R22 R22L21 R22 sample LF Liver
## 75 166 R23Ld21 R23 R23L21 R23 sample LF Liver
## 76 167 R24Ld21 R24 R24L21 R24 sample LF Liver
## 77 180 R37Ld08 R37 R37L8 R37 sample HF Liver
## 78 181 R38Ld08 R38 R38L8 R38 sample HF Liver
## 79 182 R39Ld08 R39 R39L8 R39 sample HF Liver
## 80 183 R40Ld08 R40 R40L8 R40 sample HF Liver
## 81 184 R43Ld21 R43 R41L21 R41 sample HF Liver
## 82 185 R44Ld21 R44 R42L21 R42 sample HF Liver
## 83 186 R41Ld08 R41 R43L8 R43 sample HF Liver
## 84 187 R42Ld08 R42 R44L8 R44 sample HF Liver
## 85 188 R45Ld21 R45 R45L21 R45 sample HF Liver
## 86 189 R46Ld21 R46 R46L21 R46 sample HF Liver
## 87 190 R47Ld21 R47 R47L21 R47 sample HF Liver
## 88 191 R48Ld21 R48 R48L21 R48 sample HF Liver
## 89 193 PosCtrl101 ctrl PosCtrl101 ctrl posctrl HF posctrl
## 90 194 PosCtrl102 ctrl PosCtrl102 ctrl posctrl HF posctrl
## 91 195 PosCtrl103 ctrl PosCtrl103 ctrl posctrl HF posctrl
## 92 208 R13Ud08 R13 R13U8 R13 sample LF Urine
## 93 209 R14Ud08 R14 R14U8 R14 sample LF Urine
## 94 210 R15Ud08 R15 R15U8 R15 sample LF Urine
## 95 211 R16Ud08 R16 R16U8 R16 sample LF Urine
## 96 212 R17Ud08 R17 R17U8 R17 sample LF Urine
## 97 213 R18Ud08 R18 R18U8 R18 sample LF Urine
## 98 214 R20Ud08 R20 R20U8 R20 sample LF Urine
## 99 215 R21Ud08 R21 R21U8 R21 sample LF Urine
## 100 216 R22Ud08 R22 R22U8 R22 sample LF Urine
## 101 217 R23Ud08 R23 R23U8 R23 sample LF Urine
## 102 218 R24Ud08 R24 R24U8 R24 sample LF Urine
## 103 231 R37Ud08 R37 R37U8 R37 sample HF Urine
## 104 232 R38Ud08 R38 R38U8 R38 sample HF Urine
## 105 233 R39Ud08 R39 R39U8 R39 sample HF Urine
## 106 234 R40Ud08 R40 R40U8 R40 sample HF Urine
## 107 235 R43Ud08 R43 R41U8 R41 sample HF Urine
## 108 236 R44Ud08 R44 R42U8 R42 sample HF Urine
## 109 237 R41Ud08 R41 R43U8 R43 sample HF Urine
## 110 238 R42Ud08 R42 R44U8 R44 sample HF Urine
## 111 239 R45Ud08 R45 R45U8 R45 sample HF Urine
## 112 240 R46Ud08 R46 R46U8 R46 sample HF Urine
## 113 241 R47Ud08 R47 R47U8 R47 sample HF Urine
## 114 242 R48Ud08 R48 R48U8 R48 sample HF Urine
## 115 249 R19Ud16 R19 R19U16 R19 sample LF Urine
## 116 250 R20Ud16 R20 R20U16 R20 sample LF Urine
## 117 251 R21Ud16 R21 R21U16 R21 sample LF Urine
## 118 252 R22Ud16 R22 R22U16 R22 sample LF Urine
## 119 253 R23Ud16 R23 R23U16 R23 sample LF Urine
## 120 254 R24Ud16 R24 R24U16 R24 sample LF Urine
## 121 261 R43Ud16 R43 R41U16 R41 sample HF Urine
## 122 262 R44Ud16 R44 R42U16 R42 sample HF Urine
## 123 263 R45Ud16 R45 R45U16 R45 sample HF Urine
## 124 264 R46Ud16 R46 R46U16 R46 sample HF Urine
## 125 265 R47Ud16 R47 R47U16 R47 sample HF Urine
## 126 266 R48Ud16 R48 R48U16 R48 sample HF Urine
## 127 273 R19Ud21 R19 R19U21 R19 sample LF Urine
## 128 274 R20Ud21 R20 R20U21 R20 sample LF Urine
## 129 275 R21Ud21 R21 R21U21 R21 sample LF Urine
## 130 276 R22Ud21 R22 R22U21 R22 sample LF Urine
## 131 277 R23Ud21 R23 R23U21 R23 sample LF Urine
## 132 278 R24Ud21 R24 R24U21 R24 sample LF Urine
## 133 285 R43Ud21 R43 R41U21 R41 sample HF Urine
## 134 286 R44Ud21 R44 R42U21 R42 sample HF Urine
## 135 287 R45Ud21 R45 R45U21 R45 sample HF Urine
## 136 288 R46Ud21 R46 R46U21 R46 sample HF Urine
## 137 289 R47Ud21 R47 R47U21 R47 sample HF Urine
## 138 290 R48Ud21 R48 R48U21 R48 sample HF Urine
## 139 303 R13Cd08 R13 R13C8 R13 sample LF Cecum
## 140 304 R14Cd08 R14 R14C8 R14 sample LF Cecum
## 141 305 R15Cd08 R15 R15C8 R15 sample LF Cecum
## 142 306 R16Cd08 R16 R16C8 R16 sample LF Cecum
## 143 307 R17Cd08 R17 R17C8 R17 sample LF Cecum
## 144 308 R18Cd08 R18 R18C8 R18 sample LF Cecum
## 145 309 R19Cd21 R19 R19C21 R19 sample LF Cecum
## 146 310 R20Cd21 R20 R20C21 R20 sample LF Cecum
## 147 311 R21Cd21 R21 R21C21 R21 sample LF Cecum
## 148 312 R22Cd21 R22 R22C21 R22 sample LF Cecum
## 149 313 R23Cd21 R23 R23C21 R23 sample LF Cecum
## 150 314 R24Cd21 R24 R24C21 R24 sample LF Cecum
## 151 327 R37Cd08 R37 R37C8 R37 sample HF Cecum
## 152 328 R38Cd08 R38 R38C8 R38 sample HF Cecum
## 153 329 R39Cd08 R39 R39C8 R39 sample HF Cecum
## 154 330 R40Cd08 R40 R40C8 R40 sample HF Cecum
## 155 331 R43Cd21 R43 R41C21 R41 sample HF Cecum
## 156 332 R44Cd21 R44 R42C21 R42 sample HF Cecum
## 157 333 R41Cd08 R41 R43C8 R43 sample HF Cecum
## 158 334 R42Cd08 R42 R44C8 R44 sample HF Cecum
## 159 335 R45Cd21 R45 R45C21 R45 sample HF Cecum
## 160 336 R46Cd21 R46 R46C21 R46 sample HF Cecum
## 161 337 R47Cd21 R47 R47C21 R47 sample HF Cecum
## 162 338 R48Cd21 R48 R48C21 R48 sample HF Cecum
## 163 339 R19Sd16 R19 R19S16 R19 sample LF Serum
## 164 343 Susp201 suspension Susp201 suspension suspension suspension
## 165 344 Susp202 suspension Susp202 suspension suspension suspension
## 166 345 Susp203 suspension Susp203 suspension suspension suspension
## 167 347 PosCtrl301 ctrl PosCtrl301 ctrl posctrl HF posctrl
## 168 348 PosCtrl302 ctrl PosCtrl302 ctrl posctrl HF posctrl
## 169 349 PosCtrl303 ctrl PosCtrl303 ctrl posctrl HF posctrl
## 170 351 R37Bd08 R37 R37B8 R37 sample HF Brain
## 171 352 R14Bd08 R14 R14B8 R14 sample LF Brain
## 172 353 R15Bd08 R15 R15B8 R15 sample LF Brain
## 173 354 R16Bd08 R16 R16B8 R16 sample LF Brain
## 174 367 R13Fd08 R13 R13F8 R13 sample LF Feces
## 175 368 R14Fd08 R14 R14F8 R14 sample LF Feces
## 176 369 R15Fd08 R15 R15F8 R15 sample LF Feces
## 177 370 R16Fd08 R16 R16F8 R16 sample LF Feces
## 178 371 R17Fd08 R17 R17F8 R17 sample LF Feces
## 179 372 R18Fd08 R18 R18F8 R18 sample LF Feces
## 180 373 R19Fd08 R19 R19F8 R19 sample LF Feces
## 181 374 R20Fd08 R20 R20F8 R20 sample LF Feces
## 182 375 R21Fd08 R21 R21F8 R21 sample LF Feces
## 183 376 R22Fd08 R22 R22F8 R22 sample LF Feces
## 184 377 R23Fd08 R23 R23F8 R23 sample LF Feces
## 185 378 R24Fd08 R24 R24F8 R24 sample LF Feces
## 186 391 R37Fd08 R37 R37F8 R37 sample HF Feces
## 187 392 R38Fd08 R38 R38F8 R38 sample HF Feces
## 188 393 R39Fd08 R39 R39F8 R39 sample HF Feces
## 189 394 R40Fd08 R40 R40F8 R40 sample HF Feces
## 190 395 R43Fd08 R43 R41F8 R41 sample HF Feces
## 191 396 R44Fd08 R44 R42F8 R42 sample HF Feces
## 192 397 R41Fd08 R41 R43F8 R43 sample HF Feces
## 193 398 R42Fd08 R42 R44F8 R44 sample HF Feces
## 194 399 R45Fd08 R45 R45F8 R45 sample HF Feces
## 195 400 R46Fd08 R46 R46F8 R46 sample HF Feces
## 196 401 R47Fd08 R47 R47F8 R47 sample HF Feces
## 197 402 R48Fd08 R48 R48F8 R48 sample HF Feces
## 198 409 R19Fd12 R19 R19F12 R19 sample LF Feces
## 199 410 R20Fd12 R20 R20F12 R20 sample LF Feces
## 200 411 R21Fd12 R21 R21F12 R21 sample LF Feces
## 201 412 R22Fd12 R22 R22F12 R22 sample LF Feces
## 202 413 R23Fd12 R23 R23F12 R23 sample LF Feces
## 203 414 R24Fd12 R24 R24F12 R24 sample LF Feces
## 204 421 R43Fd12 R43 R41F12 R41 sample HF Feces
## 205 422 R44Fd12 R44 R42F12 R42 sample HF Feces
## 206 423 R45Fd12 R45 R45F12 R45 sample HF Feces
## 207 424 R46Fd12 R46 R46F12 R46 sample HF Feces
## 208 425 R47Fd12 R47 R47F12 R47 sample HF Feces
## 209 426 R48Fd12 R48 R48F12 R48 sample HF Feces
## 210 433 R19Fd16 R19 R19F16 R19 sample LF Feces
## 211 434 R20Fd16 R20 R20F16 R20 sample LF Feces
## 212 435 R21Fd16 R21 R21F16 R21 sample LF Feces
## 213 436 R22Fd16 R22 R22F16 R22 sample LF Feces
## 214 437 R23Fd16 R23 R23F16 R23 sample LF Feces
## 215 438 R24Fd16 R24 R24F16 R24 sample LF Feces
## 216 445 R43Fd16 R43 R41F16 R41 sample HF Feces
## 217 446 R44Fd16 R44 R42F16 R42 sample HF Feces
## 218 447 R45Fd16 R45 R45F16 R45 sample HF Feces
## 219 448 R46Fd16 R46 R46F16 R46 sample HF Feces
## 220 449 R47Fd16 R47 R47F16 R47 sample HF Feces
## 221 450 R48Fd16 R48 R48F16 R48 sample HF Feces
## 222 457 R19Fd21 R19 R19F21 R19 sample LF Feces
## 223 458 R20Fd21 R20 R20F21 R20 sample LF Feces
## 224 459 R21Fd21 R21 R21F21 R21 sample LF Feces
## 225 460 R22Fd21 R22 R22F21 R22 sample LF Feces
## 226 461 R23Fd21 R23 R23F21 R23 sample LF Feces
## 227 462 R24Fd21 R24 R24F21 R24 sample LF Feces
## 228 469 R43Fd21 R43 R41F21 R41 sample HF Feces
## 229 470 R44Fd21 R44 R42F21 R42 sample HF Feces
## 230 471 R45Fd21 R45 R45F21 R45 sample HF Feces
## 231 472 R46Fd21 R46 R46F21 R46 sample HF Feces
## 232 473 R47Fd21 R47 R47F21 R47 sample HF Feces
## 233 474 R48Fd21 R48 R48F21 R48 sample HF Feces
## 234 491 PosCtrl401 ctrl PosCtrl401 ctrl posctrl HF posctrl
## 235 492 PosCtrl402 ctrl PosCtrl402 ctrl posctrl HF posctrl
## 236 493 PosCtrl403 ctrl PosCtrl403 ctrl posctrl HF posctrl
## day df batch_no notes org_conc sample_conc_ug
## 1 d08 16000 2 4.171 66.7360
## 2 d08 16000 2 3.367 53.8720
## 3 d08 16000 2 3.515 56.2400
## 4 d08 16000 2 4.042 64.6720
## 5 d08 16000 2 3.580 57.2800
## 6 d08 16000 2 3.839 61.4240
## 7 d08 16000 2 3.557 56.9120
## 8 d08 16000 2 3.469 55.5040
## 9 d08 16000 2 3.218 51.4880
## 10 d08 16000 2 3.630 58.0800
## 11 d08 16000 2 3.810 60.9600
## 12 d08 16000 2 3.600 57.6000
## 13 d08 16000 2 4.003 64.0480
## 14 d08 16000 2 3.735 59.7600
## 15 d08 16000 2 3.256 52.0960
## 16 d08 16000 2 3.117 49.8720
## 17 d08 16000 2 3.363 53.8080
## 18 d08 16000 2 3.712 59.3920
## 19 d08 16000 2 3.893 62.2880
## 20 d08 16000 2 3.656 58.4960
## 21 d08 16000 2 3.521 56.3360
## 22 d08 16000 2 3.248 51.9680
## 23 d08 16000 2 2.926 46.8160
## 24 d08 16000 2 3.494 55.9040
## 25 d16 16000 2 3.053 48.8480
## 26 d16 16000 2 3.040 48.6400
## 27 d16 16000 2 3.085 49.3600
## 28 d16 16000 2 3.352 53.6320
## 29 d16 16000 2 2.771 44.3360
## 30 d16 16000 2 2.985 47.7600
## 31 d16 16000 2 3.150 50.4000
## 32 d16 16000 2 2.945 47.1200
## 33 d16 16000 2 2.873 45.9680
## 34 d16 16000 2 2.477 39.6320
## 35 d16 16000 2 2.700 43.2000
## 36 d21 16000 2 2.640 42.2400
## 37 d21 16000 2 2.430 38.8800
## 38 d21 16000 2 2.271 36.3360
## 39 d21 16000 2 2.767 44.2720
## 40 d21 16000 2 3.194 51.1040
## 41 d21 16000 2 2.552 40.8320
## 42 d21 16000 2 2.714 43.4240
## 43 d21 16000 2 2.651 42.4160
## 44 d21 16000 2 2.668 42.6880
## 45 d21 16000 2 2.304 36.8640
## 46 d21 16000 2 2.140 34.2400
## 47 d21 16000 2 2.533 40.5280
## 48 d08 8000 2 0.464 3.7120
## 49 d08 8000 2 0.382 3.0560
## 50 d21 8000 2 0.318 2.5440
## 51 d21 8000 2 0.183 1.4640
## 52 d21 8000 2 0.320 2.5600
## 53 d21 8000 2 0.305 2.4400
## 54 d21 8000 2 0.364 2.9120
## 55 d21 8000 2 0.364 2.9120
## 56 d08 8000 2 0.547 4.3760
## 57 d08 8000 2 0.537 4.2960
## 58 d21 8000 2 0.227 1.8160
## 59 d08 8000 2 0.635 5.0800
## 60 d08 8000 2 0.538 4.3040
## 61 d21 8000 2 0.326 2.6080
## 62 d21 8000 2 0.203 1.6240
## 63 d21 8000 2 0.268 2.1440
## 64 d21 8000 2 0.301 2.4080
## 65 d08 80000 2 1.949 155.9200
## 66 d08 80000 2 2.332 186.5600
## 67 d08 80000 2 2.189 175.1200
## 68 d08 80000 2 2.134 170.7200
## 69 d08 80000 2 2.195 175.6000
## 70 d08 80000 2 1.954 156.3200
## 71 d21 80000 2 1.772 141.7600
## 72 d21 80000 2 1.906 152.4800
## 73 d21 80000 2 1.702 136.1600
## 74 d21 80000 2 1.962 156.9600
## 75 d21 80000 2 1.813 145.0400
## 76 d21 80000 2 1.728 138.2400
## 77 d08 80000 2 2.393 191.4400
## 78 d08 80000 2 2.554 204.3200
## 79 d08 80000 2 2.357 188.5600
## 80 d08 80000 2 2.315 185.2000
## 81 d21 80000 2 1.832 146.5600
## 82 d21 80000 2 1.787 142.9600
## 83 d08 80000 2 2.527 202.1600
## 84 d08 80000 2 2.429 194.3200
## 85 d21 80000 2 1.898 151.8400
## 86 d21 80000 2 1.721 137.6800
## 87 d21 80000 2 1.801 144.0800
## 88 d21 80000 2 1.951 156.0800
## 89 d21 NA 2 5 ng/mL positive control 5.865 NA
## 90 d21 NA 2 2.5 ng/mL positive control 2.915 NA
## 91 d21 NA 2 1.25 ng/mL positive control 1.475 NA
## 92 d08 400 3 2.004 0.8016
## 93 d08 400 3 0.622 0.2488
## 94 d08 400 3 1.418 0.5672
## 95 d08 400 3 1.864 0.7456
## 96 d08 400 3 1.885 0.7540
## 97 d08 400 3 2.327 0.9308
## 98 d08 400 3 1.635 0.6540
## 99 d08 400 3 1.849 0.7396
## 100 d08 400 3 2.059 0.8236
## 101 d08 400 3 1.024 0.4096
## 102 d08 400 3 5.863 2.3452
## 103 d08 400 3 1.786 0.7144
## 104 d08 400 3 1.123 0.4492
## 105 d08 400 3 1.518 0.6072
## 106 d08 400 3 1.519 0.6076
## 107 d08 400 3 1.128 0.4512
## 108 d08 400 3 0.856 0.3424
## 109 d08 400 3 1.279 0.5116
## 110 d08 400 3 1.413 0.5652
## 111 d08 400 3 1.524 0.6096
## 112 d08 400 3 1.566 0.6264
## 113 d08 400 3 0.826 0.3304
## 114 d08 400 3 2.966 1.1864
## 115 d16 400 3 5.603 2.2412
## 116 d16 400 3 2.268 0.9072
## 117 d16 400 3 4.073 1.6292
## 118 d16 400 3 2.651 1.0604
## 119 d16 400 3 0.808 0.3232
## 120 d16 400 3 2.438 0.9752
## 121 d16 400 3 3.121 1.2484
## 122 d16 400 3 1.588 0.6352
## 123 d16 400 3 2.935 1.1740
## 124 d16 400 3 7.665 3.0660
## 125 d16 400 3 1.781 0.7124
## 126 d16 400 3 2.645 1.0580
## 127 d21 400 3 0.882 0.3528
## 128 d21 400 3 0.381 0.1524
## 129 d21 400 3 0.297 0.1188
## 130 d21 400 3 1.015 0.4060
## 131 d21 400 3 0.620 0.2480
## 132 d21 400 3 0.584 0.2336
## 133 d21 400 3 0.465 0.1860
## 134 d21 400 3 1.461 0.5844
## 135 d21 400 3 0.601 0.2404
## 136 d21 400 3 0.445 0.1780
## 137 d21 400 3 0.293 0.1172
## 138 d21 400 3 0.267 0.1068
## 139 d08 1000 3 0.844 0.8440
## 140 d08 1000 3 0.765 0.7650
## 141 d08 1000 3 0.903 0.9030
## 142 d08 1000 3 0.975 0.9750
## 143 d08 1000 3 1.025 1.0250
## 144 d08 1000 3 0.930 0.9300
## 145 d21 1000 3 0.740 0.7400
## 146 d21 1000 3 0.881 0.8810
## 147 d21 1000 3 0.526 0.5260
## 148 d21 1000 3 0.852 0.8520
## 149 d21 1000 3 0.866 0.8660
## 150 d21 1000 3 0.590 0.5900
## 151 d08 1000 3 1.881 1.8810
## 152 d08 1000 3 1.592 1.5920
## 153 d08 1000 3 1.447 1.4470
## 154 d08 1000 3 0.919 0.9190
## 155 d21 1000 3 1.139 1.1390
## 156 d21 1000 3 1.224 1.2240
## 157 d08 1000 3 1.812 1.8120
## 158 d08 1000 3 1.406 1.4060
## 159 d21 1000 3 1.127 1.1270
## 160 d21 1000 3 1.057 1.0570
## 161 d21 1000 3 1.187 1.1870
## 162 d21 1000 3 1.100 1.1000
## 163 d16 16000 3 3.148 50.3680
## 164 400000 3 triplicate 3.394 1357.6000
## 165 400000 3 triplicate 3.364 1345.6000
## 166 400000 3 triplicate 3.396 1358.4000
## 167 d08 NA 3 5 ng/mL positive control 5.973 NA
## 168 d08 NA 3 2.5 ng/mL positive control 2.977 NA
## 169 d08 NA 3 1.25 ng/mL positive control 1.562 NA
## 170 d08 8000 4 0.487 3.8960
## 171 d08 8000 4 0.524 4.1920
## 172 d08 8000 4 0.583 4.6640
## 173 d08 8000 4 0.499 3.9920
## 174 d08 1000 4 1.089 1.0890
## 175 d08 1000 4 1.888 1.8880
## 176 d08 1000 4 2.179 2.1790
## 177 d08 1000 4 1.601 1.6010
## 178 d08 1000 4 1.688 1.6880
## 179 d08 1000 4 1.571 1.5710
## 180 d08 1000 4 1.857 1.8570
## 181 d08 1000 4 1.369 1.3690
## 182 d08 1000 4 1.359 1.3590
## 183 d08 1000 4 1.407 1.4070
## 184 d08 1000 4 1.552 1.5520
## 185 d08 1000 4 1.779 1.7790
## 186 d08 1000 4 4.078 4.0780
## 187 d08 1000 4 3.737 3.7370
## 188 d08 1000 4 3.522 3.5220
## 189 d08 1000 4 2.262 2.2620
## 190 d08 1000 4 4.449 4.4490
## 191 d08 1000 4 3.248 3.2480
## 192 d08 1000 4 4.056 4.0560
## 193 d08 1000 4 4.650 4.6500
## 194 d08 1000 4 3.577 3.5770
## 195 d08 1000 4 3.170 3.1700
## 196 d08 1000 4 2.915 2.9150
## 197 d08 1000 4 2.208 2.2080
## 198 d12 1000 4 0.864 0.8640
## 199 d12 1000 4 1.527 1.5270
## 200 d12 1000 4 1.658 1.6580
## 201 d12 1000 4 1.084 1.0840
## 202 d12 1000 4 1.739 1.7390
## 203 d12 1000 4 1.198 1.1980
## 204 d12 1000 4 2.455 2.4550
## 205 d12 1000 4 2.300 2.3000
## 206 d12 1000 4 3.063 3.0630
## 207 d12 1000 4 2.709 2.7090
## 208 d12 1000 4 2.529 2.5290
## 209 d12 1000 4 1.892 1.8920
## 210 d16 1000 4 1.200 1.2000
## 211 d16 1000 4 1.198 1.1980
## 212 d16 1000 4 1.101 1.1010
## 213 d16 1000 4 1.383 1.3830
## 214 d16 1000 4 1.780 1.7800
## 215 d16 1000 4 1.855 1.8550
## 216 d16 1000 4 2.628 2.6280
## 217 d16 1000 4 2.406 2.4060
## 218 d16 1000 4 2.675 2.6750
## 219 d16 1000 4 1.835 1.8350
## 220 d16 1000 4 2.181 2.1810
## 221 d16 1000 4 1.628 1.6280
## 222 d21 1000 4 1.056 1.0560
## 223 d21 1000 4 1.179 1.1790
## 224 d21 1000 4 1.025 1.0250
## 225 d21 1000 4 1.234 1.2340
## 226 d21 1000 4 0.997 0.9970
## 227 d21 1000 4 0.877 0.8770
## 228 d21 1000 4 2.103 2.1030
## 229 d21 1000 4 2.337 2.3370
## 230 d21 1000 4 2.746 2.7460
## 231 d21 1000 4 1.316 1.3160
## 232 d21 1000 4 2.554 2.5540
## 233 d21 1000 4 1.335 1.3350
## 234 d08 NA 4 5 ng/mL positive control 5.693 NA
## 235 d08 NA 4 2.5 ng/mL positive control 2.889 NA
## 236 d08 NA 4 1.25 ng/mL positive control 1.521 NA
## pfos_t_amt pfos_b_amt pfos_l_amt bl_ratio dayfeed matfeed br_pct
## 1 4.175 1.331 2.802 0.4750 d08_LF Serum_LF 0.31880240
## 2 3.342 1.194 2.223 0.5371 d08_LF Serum_LF 0.35727110
## 3 3.482 1.342 2.268 0.5917 d08_LF Serum_LF 0.38541068
## 4 4.022 1.253 2.550 0.4914 d08_LF Serum_LF 0.31153655
## 5 3.563 1.151 2.387 0.4822 d08_LF Serum_LF 0.32304238
## 6 3.816 1.340 2.386 0.5616 d08_LF Serum_LF 0.35115304
## 7 3.535 1.138 2.422 0.4699 d08_LF Serum_LF 0.32192362
## 8 3.443 1.261 2.061 0.6118 d08_LF Serum_LF 0.36625036
## 9 3.222 1.061 2.189 0.4847 d08_LF Serum_LF 0.32929857
## 10 3.609 1.347 2.358 0.5712 d08_LF Serum_LF 0.37323358
## 11 3.796 1.183 2.543 0.4652 d08_LF Serum_LF 0.31164384
## 12 3.567 1.299 2.315 0.5611 d08_LF Serum_LF 0.36417157
## 13 3.975 1.505 2.393 0.6289 d08_HF Serum_HF 0.37861635
## 14 3.705 1.433 2.391 0.5993 d08_HF Serum_HF 0.38677463
## 15 3.229 1.163 2.014 0.5775 d08_HF Serum_HF 0.36017343
## 16 3.100 0.935 2.033 0.4599 d08_HF Serum_HF 0.30161290
## 17 3.338 1.321 2.199 0.6007 d08_HF Serum_HF 0.39574596
## 18 3.669 1.253 2.434 0.5148 d08_HF Serum_HF 0.34150995
## 19 3.870 1.326 2.513 0.5277 d08_HF Serum_HF 0.34263566
## 20 3.626 1.280 2.358 0.5428 d08_HF Serum_HF 0.35300607
## 21 3.478 1.335 2.321 0.5752 d08_HF Serum_HF 0.38384129
## 22 3.229 0.942 2.113 0.4458 d08_HF Serum_HF 0.29173119
## 23 2.913 1.062 1.880 0.5649 d08_HF Serum_HF 0.36457261
## 24 3.475 1.329 2.207 0.6022 d08_HF Serum_HF 0.38244604
## 25 3.039 1.082 1.911 0.5662 d16_LF Serum_LF 0.35603817
## 26 3.019 1.199 1.952 0.6142 d16_LF Serum_LF 0.39715137
## 27 3.069 1.154 1.801 0.6408 d16_LF Serum_LF 0.37601825
## 28 3.323 1.139 2.234 0.5098 d16_LF Serum_LF 0.34276256
## 29 2.767 0.917 1.869 0.4906 d16_LF Serum_LF 0.33140585
## 30 2.957 0.964 1.979 0.4871 d16_HF Serum_HF 0.32600609
## 31 3.116 1.143 1.913 0.5975 d16_HF Serum_HF 0.36681643
## 32 2.924 1.035 1.697 0.6099 d16_HF Serum_HF 0.35396717
## 33 2.859 0.876 1.779 0.4924 d16_HF Serum_HF 0.30640084
## 34 2.463 0.978 1.541 0.6347 d16_HF Serum_HF 0.39707674
## 35 2.685 0.948 1.668 0.5683 d16_HF Serum_HF 0.35307263
## 36 2.617 1.094 1.574 0.6950 d21_LF Serum_LF 0.41803592
## 37 2.421 0.929 1.447 0.6420 d21_LF Serum_LF 0.38372573
## 38 2.256 0.803 1.447 0.5549 d21_LF Serum_LF 0.35593972
## 39 2.754 1.003 1.511 0.6638 d21_LF Serum_LF 0.36419753
## 40 3.181 1.280 1.921 0.6663 d21_LF Serum_LF 0.40238919
## 41 2.540 1.073 1.404 0.7642 d21_LF Serum_LF 0.42244094
## 42 2.701 1.115 1.660 0.6717 d21_HF Serum_HF 0.41281007
## 43 2.631 1.157 1.612 0.7177 d21_HF Serum_HF 0.43975675
## 44 2.656 0.907 1.697 0.5345 d21_HF Serum_HF 0.34149096
## 45 2.294 0.788 1.443 0.5461 d21_HF Serum_HF 0.34350480
## 46 2.129 0.777 1.171 0.6635 d21_HF Serum_HF 0.36496008
## 47 2.518 0.999 1.501 0.6656 d21_HF Serum_HF 0.39674345
## 48 0.467 0.079 0.454 0.1740 d08_LF Brain_LF 0.16916488
## 49 0.385 0.057 0.395 0.1443 d08_LF Brain_LF 0.14805195
## 50 0.321 0.059 0.324 0.1821 d21_LF Brain_LF 0.18380062
## 51 0.190 0.053 0.213 0.2488 d21_LF Brain_LF 0.27894737
## 52 0.324 0.061 0.334 0.1826 d21_LF Brain_LF 0.18827160
## 53 0.308 0.049 0.327 0.1498 d21_LF Brain_LF 0.15909091
## 54 0.370 0.055 0.376 0.1463 d21_LF Brain_LF 0.14864865
## 55 0.367 0.060 0.367 0.1635 d21_LF Brain_LF 0.16348774
## 56 0.550 0.082 0.527 0.1556 d08_HF Brain_HF 0.14909091
## 57 0.541 0.124 0.500 0.2480 d08_HF Brain_HF 0.22920518
## 58 0.231 0.063 0.238 0.2647 d21_HF Brain_HF 0.27272727
## 59 0.639 0.103 0.625 0.1648 d08_HF Brain_HF 0.16118936
## 60 0.539 0.073 0.515 0.1417 d08_HF Brain_HF 0.13543599
## 61 0.328 0.046 0.352 0.1307 d21_HF Brain_HF 0.14024390
## 62 0.207 0.045 0.231 0.1948 d21_HF Brain_HF 0.21739130
## 63 0.274 0.046 0.185 0.2486 d21_HF Brain_HF 0.16788321
## 64 0.305 0.057 0.312 0.1827 d21_HF Brain_HF 0.18688525
## 65 1.937 0.543 1.429 0.3800 d08_LF Liver_LF 0.28033041
## 66 2.310 0.380 1.861 0.2042 d08_LF Liver_LF 0.16450216
## 67 2.176 0.477 1.623 0.2939 d08_LF Liver_LF 0.21920956
## 68 2.117 0.697 1.494 0.4665 d08_LF Liver_LF 0.32923949
## 69 2.184 0.378 1.855 0.2038 d08_LF Liver_LF 0.17307692
## 70 1.944 0.323 1.460 0.2212 d08_LF Liver_LF 0.16615226
## 71 1.766 0.458 1.436 0.3189 d21_LF Liver_LF 0.25934315
## 72 1.895 0.782 1.237 0.6322 d21_LF Liver_LF 0.41266491
## 73 1.699 0.561 1.198 0.4683 d21_LF Liver_LF 0.33019423
## 74 1.948 0.353 1.405 0.2512 d21_LF Liver_LF 0.18121150
## 75 1.806 0.351 1.340 0.2619 d21_LF Liver_LF 0.19435216
## 76 1.723 0.425 1.254 0.3389 d21_LF Liver_LF 0.24666280
## 77 2.376 0.765 1.628 0.4699 d08_HF Liver_HF 0.32196970
## 78 2.533 0.799 1.815 0.4402 d08_HF Liver_HF 0.31543624
## 79 2.346 0.783 1.655 0.4731 d08_HF Liver_HF 0.33375959
## 80 2.307 0.588 1.676 0.3508 d08_HF Liver_HF 0.25487646
## 81 1.821 0.646 1.306 0.4946 d21_HF Liver_HF 0.35475014
## 82 1.779 0.549 1.213 0.4526 d21_HF Liver_HF 0.30860034
## 83 2.516 0.803 1.789 0.4489 d08_HF Liver_HF 0.31915739
## 84 2.418 0.615 1.649 0.3730 d08_HF Liver_HF 0.25434243
## 85 1.889 0.468 1.290 0.3628 d21_HF Liver_HF 0.24775013
## 86 1.720 0.523 1.157 0.4520 d21_HF Liver_HF 0.30406977
## 87 1.793 0.548 1.392 0.3937 d21_HF Liver_HF 0.30563302
## 88 1.940 0.493 1.374 0.3588 d21_HF Liver_HF 0.25412371
## 89 5.843 0.503 5.748 0.0875 d21_HF posctrl_HF 0.08608591
## 90 2.904 0.259 2.897 0.0894 d21_HF posctrl_HF 0.08918733
## 91 1.474 0.130 1.417 0.0917 d21_HF posctrl_HF 0.08819539
## 92 1.994 0.913 1.071 0.8525 d08_LF Urine_LF 0.45787362
## 93 0.621 0.284 0.337 0.8427 d08_LF Urine_LF 0.45732689
## 94 1.411 0.745 0.710 1.0493 d08_LF Urine_LF 0.52799433
## 95 1.854 0.946 0.919 1.0294 d08_LF Urine_LF 0.51024811
## 96 1.872 0.982 0.876 1.1210 d08_LF Urine_LF 0.52457265
## 97 2.309 1.238 1.067 1.1603 d08_LF Urine_LF 0.53616284
## 98 1.635 0.914 0.756 1.2090 d08_LF Urine_LF 0.55902141
## 99 1.836 1.095 0.781 1.4020 d08_LF Urine_LF 0.59640523
## 100 2.046 1.153 0.920 1.2533 d08_LF Urine_LF 0.56353861
## 101 1.020 0.585 0.451 1.2971 d08_LF Urine_LF 0.57352941
## 102 5.905 3.178 2.756 1.1531 d08_LF Urine_LF 0.53818798
## 103 1.788 1.075 0.761 1.4126 d08_HF Urine_HF 0.60123043
## 104 1.120 0.605 0.545 1.1101 d08_HF Urine_HF 0.54017857
## 105 1.514 0.947 0.580 1.6328 d08_HF Urine_HF 0.62549538
## 106 1.516 0.857 0.691 1.2402 d08_HF Urine_HF 0.56530343
## 107 1.135 0.657 0.487 1.3491 d08_HF Urine_HF 0.57885463
## 108 0.854 0.521 0.335 1.5552 d08_HF Urine_HF 0.61007026
## 109 1.274 0.700 0.573 1.2216 d08_HF Urine_HF 0.54945055
## 110 1.407 0.774 0.643 1.2037 d08_HF Urine_HF 0.55010661
## 111 1.518 0.798 0.603 1.3234 d08_HF Urine_HF 0.52569170
## 112 1.582 0.849 0.758 1.1201 d08_HF Urine_HF 0.53666245
## 113 0.824 0.522 0.321 1.6262 d08_HF Urine_HF 0.63349515
## 114 2.962 1.682 1.360 1.2368 d08_HF Urine_HF 0.56785955
## 115 5.580 2.348 3.339 0.7032 d16_LF Urine_LF 0.42078853
## 116 2.272 1.056 1.224 0.8627 d16_LF Urine_LF 0.46478873
## 117 4.064 1.462 2.677 0.5461 d16_LF Urine_LF 0.35974409
## 118 2.638 1.101 1.589 0.6929 d16_LF Urine_LF 0.41736164
## 119 0.807 0.370 0.433 0.8545 d16_LF Urine_LF 0.45848823
## 120 2.426 1.161 1.315 0.8829 d16_LF Urine_LF 0.47856554
## 121 3.106 1.435 1.698 0.8451 d16_HF Urine_HF 0.46200901
## 122 1.582 0.776 0.827 0.9383 d16_HF Urine_HF 0.49051833
## 123 2.927 1.372 1.654 0.8295 d16_HF Urine_HF 0.46873932
## 124 7.709 3.503 4.355 0.8044 d16_HF Urine_HF 0.45440394
## 125 1.773 0.872 0.910 0.9582 d16_HF Urine_HF 0.49182177
## 126 2.647 1.307 1.372 0.9526 d16_HF Urine_HF 0.49376653
## 127 0.878 0.474 0.414 1.1449 d21_LF Urine_LF 0.53986333
## 128 0.381 0.176 0.212 0.8302 d21_LF Urine_LF 0.46194226
## 129 0.296 0.157 0.139 1.1295 d21_LF Urine_LF 0.53040541
## 130 1.011 0.520 0.487 1.0678 d21_LF Urine_LF 0.51434224
## 131 0.619 0.267 0.356 0.7500 d21_LF Urine_LF 0.43134087
## 132 0.582 0.285 0.302 0.9437 d21_LF Urine_LF 0.48969072
## 133 0.464 0.248 0.221 1.1222 d21_HF Urine_HF 0.53448276
## 134 1.458 0.737 0.740 0.9959 d21_HF Urine_HF 0.50548697
## 135 0.600 0.319 0.295 1.0814 d21_HF Urine_HF 0.53166667
## 136 0.445 0.212 0.233 0.9099 d21_HF Urine_HF 0.47640449
## 137 0.293 0.170 0.127 1.3386 d21_HF Urine_HF 0.58020478
## 138 0.267 0.141 0.127 1.1102 d21_HF Urine_HF 0.52808989
## 139 0.842 0.168 0.676 0.2485 d08_LF Cecum_LF 0.19952494
## 140 0.763 0.135 0.624 0.2163 d08_LF Cecum_LF 0.17693316
## 141 0.901 0.176 0.727 0.2421 d08_LF Cecum_LF 0.19533851
## 142 0.972 0.196 0.800 0.2450 d08_LF Cecum_LF 0.20164609
## 143 1.023 0.175 0.857 0.2042 d08_LF Cecum_LF 0.17106549
## 144 0.929 0.161 0.769 0.2094 d08_LF Cecum_LF 0.17330463
## 145 0.739 0.153 0.594 0.2576 d21_LF Cecum_LF 0.20703654
## 146 0.881 0.109 0.706 0.1544 d21_LF Cecum_LF 0.12372304
## 147 0.526 0.088 0.439 0.2005 d21_LF Cecum_LF 0.16730038
## 148 0.850 0.186 0.679 0.2739 d21_LF Cecum_LF 0.21882353
## 149 0.864 0.136 0.707 0.1924 d21_LF Cecum_LF 0.15740741
## 150 0.591 0.109 0.474 0.2300 d21_LF Cecum_LF 0.18443316
## 151 1.879 0.383 1.494 0.2564 d08_HF Cecum_HF 0.20383183
## 152 1.590 0.298 1.285 0.2319 d08_HF Cecum_HF 0.18742138
## 153 1.444 0.293 1.156 0.2535 d08_HF Cecum_HF 0.20290859
## 154 0.917 0.176 0.748 0.2353 d08_HF Cecum_HF 0.19193021
## 155 1.135 0.225 0.909 0.2475 d21_HF Cecum_HF 0.19823789
## 156 1.221 0.271 0.970 0.2794 d21_HF Cecum_HF 0.22194922
## 157 1.809 0.400 1.426 0.2805 d08_HF Cecum_HF 0.22111664
## 158 1.404 0.276 1.128 0.2447 d08_HF Cecum_HF 0.19658120
## 159 1.126 0.207 0.935 0.2214 d21_HF Cecum_HF 0.18383659
## 160 1.057 0.198 0.874 0.2265 d21_HF Cecum_HF 0.18732261
## 161 1.184 0.235 0.958 0.2453 d21_HF Cecum_HF 0.19847973
## 162 1.097 0.196 0.914 0.2144 d21_HF Cecum_HF 0.17866910
## 163 3.146 0.982 2.241 0.4382 d16_LF Serum_LF 0.31214240
## 164 3.397 0.816 2.647 0.3083 _ suspension_ 0.24021195
## 165 3.360 0.786 2.601 0.3022 _ suspension_ 0.23392857
## 166 3.399 0.796 2.630 0.3027 _ suspension_ 0.23418653
## 167 5.971 0.659 5.384 0.1224 d08_HF posctrl_HF 0.11036677
## 168 2.979 0.315 2.663 0.1183 d08_HF posctrl_HF 0.10574018
## 169 1.561 0.174 1.412 0.1232 d08_HF posctrl_HF 0.11146701
## 170 0.489 0.064 0.433 0.1478 d08_HF Brain_HF 0.13087935
## 171 0.526 0.066 0.476 0.1387 d08_LF Brain_LF 0.12547529
## 172 0.585 0.066 0.530 0.1245 d08_LF Brain_LF 0.11282051
## 173 0.502 0.068 0.441 0.1542 d08_LF Brain_LF 0.13545817
## 174 1.088 0.220 0.882 0.2494 d08_LF Feces_LF 0.20220588
## 175 1.883 0.398 1.507 0.2641 d08_LF Feces_LF 0.21136484
## 176 2.169 0.433 1.758 0.2463 d08_LF Feces_LF 0.19963117
## 177 1.597 0.307 1.320 0.2326 d08_LF Feces_LF 0.19223544
## 178 1.682 0.313 1.388 0.2255 d08_LF Feces_LF 0.18608799
## 179 1.564 0.285 1.298 0.2196 d08_LF Feces_LF 0.18222506
## 180 1.848 0.358 1.526 0.2346 d08_LF Feces_LF 0.19372294
## 181 1.365 0.258 1.123 0.2297 d08_LF Feces_LF 0.18901099
## 182 1.352 0.271 1.098 0.2468 d08_LF Feces_LF 0.20044379
## 183 1.405 0.244 1.178 0.2071 d08_LF Feces_LF 0.17366548
## 184 1.542 0.297 1.264 0.2350 d08_LF Feces_LF 0.19260700
## 185 1.774 0.360 1.433 0.2512 d08_LF Feces_LF 0.20293123
## 186 4.075 0.865 3.276 0.2640 d08_HF Feces_HF 0.21226994
## 187 3.732 0.741 3.048 0.2431 d08_HF Feces_HF 0.19855305
## 188 3.516 0.708 2.837 0.2496 d08_HF Feces_HF 0.20136519
## 189 2.256 0.470 1.804 0.2605 d08_HF Feces_HF 0.20833333
## 190 4.427 0.873 3.625 0.2408 d08_HF Feces_HF 0.19719901
## 191 3.250 0.624 2.651 0.2354 d08_HF Feces_HF 0.19200000
## 192 4.057 0.750 3.315 0.2262 d08_HF Feces_HF 0.18486566
## 193 4.650 0.905 3.775 0.2397 d08_HF Feces_HF 0.19462366
## 194 3.570 0.534 2.964 0.1802 d08_HF Feces_HF 0.14957983
## 195 3.168 0.630 2.565 0.2456 d08_HF Feces_HF 0.19886364
## 196 2.906 0.564 2.370 0.2380 d08_HF Feces_HF 0.19408121
## 197 2.208 0.410 1.798 0.2280 d08_HF Feces_HF 0.18568841
## 198 0.864 0.148 0.735 0.2014 d12_LF Feces_LF 0.17129630
## 199 1.527 0.335 1.209 0.2771 d12_LF Feces_LF 0.21938441
## 200 1.660 0.390 1.286 0.3033 d12_LF Feces_LF 0.23493976
## 201 1.083 0.247 0.839 0.2944 d12_LF Feces_LF 0.22807018
## 202 1.735 0.333 1.402 0.2375 d12_LF Feces_LF 0.19193084
## 203 1.195 0.240 0.959 0.2503 d12_LF Feces_LF 0.20083682
## 204 2.449 0.526 1.984 0.2651 d12_HF Feces_HF 0.21478154
## 205 2.341 0.551 1.872 0.2943 d12_HF Feces_HF 0.23536950
## 206 3.051 0.662 2.463 0.2688 d12_HF Feces_HF 0.21697804
## 207 2.712 0.579 2.172 0.2666 d12_HF Feces_HF 0.21349558
## 208 2.518 0.556 1.992 0.2791 d12_HF Feces_HF 0.22081017
## 209 1.895 0.381 1.528 0.2493 d12_HF Feces_HF 0.20105541
## 210 1.292 0.210 1.076 0.1952 d16_LF Feces_LF 0.16253870
## 211 1.225 0.239 0.996 0.2400 d16_LF Feces_LF 0.19510204
## 212 1.104 0.216 0.902 0.2395 d16_LF Feces_LF 0.19565217
## 213 1.384 0.261 1.124 0.2322 d16_LF Feces_LF 0.18858382
## 214 1.777 0.357 1.467 0.2434 d16_LF Feces_LF 0.20090039
## 215 1.852 0.379 1.484 0.2554 d16_LF Feces_LF 0.20464363
## 216 2.626 0.637 2.034 0.3132 d16_HF Feces_HF 0.24257426
## 217 2.401 0.469 1.894 0.2476 d16_HF Feces_HF 0.19533528
## 218 2.674 0.554 2.109 0.2627 d16_HF Feces_HF 0.20718025
## 219 1.828 0.385 1.458 0.2641 d16_HF Feces_HF 0.21061269
## 220 2.182 0.472 1.726 0.2735 d16_HF Feces_HF 0.21631531
## 221 1.626 0.343 1.298 0.2643 d16_HF Feces_HF 0.21094711
## 222 1.061 0.234 0.851 0.2750 d21_LF Feces_LF 0.22054665
## 223 1.186 0.288 0.944 0.3051 d21_LF Feces_LF 0.24283305
## 224 1.030 0.239 0.842 0.2838 d21_LF Feces_LF 0.23203883
## 225 1.236 0.309 0.956 0.3232 d21_LF Feces_LF 0.25000000
## 226 0.999 0.203 0.839 0.2420 d21_LF Feces_LF 0.20320320
## 227 0.880 0.181 0.713 0.2539 d21_LF Feces_LF 0.20568182
## 228 2.099 0.452 1.621 0.2788 d21_HF Feces_HF 0.21534064
## 229 2.345 0.578 1.803 0.3206 d21_HF Feces_HF 0.24648188
## 230 2.748 0.610 2.106 0.2896 d21_HF Feces_HF 0.22197962
## 231 4.932 0.987 3.931 0.2511 d21_HF Feces_HF 0.20012165
## 232 12.084 2.551 8.211 0.3107 d21_HF Feces_HF 0.21110559
## 233 1.504 0.448 0.851 0.5264 d21_HF Feces_HF 0.29787234
## 234 6.571 0.666 5.744 0.1159 d08_HF posctrl_HF 0.10135444
## 235 2.973 0.336 2.626 0.1280 d08_HF posctrl_HF 0.11301715
## 236 60.549 6.677 53.119 0.1257 d08_HF posctrl_HF 0.11027432
## l_pct
## 1 0.6811976
## 2 0.6427289
## 3 0.6145893
## 4 0.6884635
## 5 0.6769576
## 6 0.6488470
## 7 0.6780764
## 8 0.6337496
## 9 0.6707014
## 10 0.6267664
## 11 0.6883562
## 12 0.6358284
## 13 0.6213836
## 14 0.6132254
## 15 0.6398266
## 16 0.6983871
## 17 0.6042540
## 18 0.6584901
## 19 0.6573643
## 20 0.6469939
## 21 0.6161587
## 22 0.7082688
## 23 0.6354274
## 24 0.6175540
## 25 0.6439618
## 26 0.6028486
## 27 0.6239818
## 28 0.6572374
## 29 0.6685941
## 30 0.6739939
## 31 0.6331836
## 32 0.6460328
## 33 0.6935992
## 34 0.6029233
## 35 0.6469274
## 36 0.5819641
## 37 0.6162743
## 38 0.6440603
## 39 0.6358025
## 40 0.5976108
## 41 0.5775591
## 42 0.5871899
## 43 0.5602433
## 44 0.6585090
## 45 0.6564952
## 46 0.6350399
## 47 0.6032566
## 48 0.8308351
## 49 0.8519481
## 50 0.8161994
## 51 0.7210526
## 52 0.8117284
## 53 0.8409091
## 54 0.8513514
## 55 0.8365123
## 56 0.8509091
## 57 0.7707948
## 58 0.7272727
## 59 0.8388106
## 60 0.8645640
## 61 0.8597561
## 62 0.7826087
## 63 0.8321168
## 64 0.8131148
## 65 0.7196696
## 66 0.8354978
## 67 0.7807904
## 68 0.6707605
## 69 0.8269231
## 70 0.8338477
## 71 0.7406569
## 72 0.5873351
## 73 0.6698058
## 74 0.8187885
## 75 0.8056478
## 76 0.7533372
## 77 0.6780303
## 78 0.6845638
## 79 0.6662404
## 80 0.7451235
## 81 0.6452499
## 82 0.6913997
## 83 0.6808426
## 84 0.7456576
## 85 0.7522499
## 86 0.6959302
## 87 0.6943670
## 88 0.7458763
## 89 0.9139141
## 90 0.9108127
## 91 0.9118046
## 92 0.5421264
## 93 0.5426731
## 94 0.4720057
## 95 0.4897519
## 96 0.4754274
## 97 0.4638372
## 98 0.4409786
## 99 0.4035948
## 100 0.4364614
## 101 0.4264706
## 102 0.4618120
## 103 0.3987696
## 104 0.4598214
## 105 0.3745046
## 106 0.4346966
## 107 0.4211454
## 108 0.3899297
## 109 0.4505495
## 110 0.4498934
## 111 0.4743083
## 112 0.4633375
## 113 0.3665049
## 114 0.4321404
## 115 0.5792115
## 116 0.5352113
## 117 0.6402559
## 118 0.5826384
## 119 0.5415118
## 120 0.5214345
## 121 0.5379910
## 122 0.5094817
## 123 0.5312607
## 124 0.5455961
## 125 0.5081782
## 126 0.5062335
## 127 0.4601367
## 128 0.5380577
## 129 0.4695946
## 130 0.4856578
## 131 0.5686591
## 132 0.5103093
## 133 0.4655172
## 134 0.4945130
## 135 0.4683333
## 136 0.5235955
## 137 0.4197952
## 138 0.4719101
## 139 0.8004751
## 140 0.8230668
## 141 0.8046615
## 142 0.7983539
## 143 0.8289345
## 144 0.8266954
## 145 0.7929635
## 146 0.8762770
## 147 0.8326996
## 148 0.7811765
## 149 0.8425926
## 150 0.8155668
## 151 0.7961682
## 152 0.8125786
## 153 0.7970914
## 154 0.8080698
## 155 0.8017621
## 156 0.7780508
## 157 0.7788834
## 158 0.8034188
## 159 0.8161634
## 160 0.8126774
## 161 0.8015203
## 162 0.8213309
## 163 0.6878576
## 164 0.7597880
## 165 0.7660714
## 166 0.7658135
## 167 0.8896332
## 168 0.8942598
## 169 0.8885330
## 170 0.8691207
## 171 0.8745247
## 172 0.8871795
## 173 0.8645418
## 174 0.7977941
## 175 0.7886352
## 176 0.8003688
## 177 0.8077646
## 178 0.8139120
## 179 0.8177749
## 180 0.8062771
## 181 0.8109890
## 182 0.7995562
## 183 0.8263345
## 184 0.8073930
## 185 0.7970688
## 186 0.7877301
## 187 0.8014469
## 188 0.7986348
## 189 0.7916667
## 190 0.8028010
## 191 0.8080000
## 192 0.8151343
## 193 0.8053763
## 194 0.8504202
## 195 0.8011364
## 196 0.8059188
## 197 0.8143116
## 198 0.8287037
## 199 0.7806156
## 200 0.7650602
## 201 0.7719298
## 202 0.8080692
## 203 0.7991632
## 204 0.7852185
## 205 0.7646305
## 206 0.7830220
## 207 0.7865044
## 208 0.7791898
## 209 0.7989446
## 210 0.8374613
## 211 0.8048980
## 212 0.8043478
## 213 0.8114162
## 214 0.7990996
## 215 0.7953564
## 216 0.7574257
## 217 0.8046647
## 218 0.7928197
## 219 0.7893873
## 220 0.7836847
## 221 0.7890529
## 222 0.7794533
## 223 0.7571669
## 224 0.7679612
## 225 0.7500000
## 226 0.7967968
## 227 0.7943182
## 228 0.7846594
## 229 0.7535181
## 230 0.7780204
## 231 0.7998783
## 232 0.7888944
## 233 0.7021277
## 234 0.8986456
## 235 0.8869828
## 236 0.8897257
7.2 SYSTEMIC MEASUREMENTS
7.2.1 Blood serum data
Investigation of br-PFOS % in treatment groups in serum samples on Day 8, Day 16 and Day 21.
7.2.1.1 Prepare data
# Load data
load("R_objects/pfos_isomer_data.Rdata")
# Subset
dat.clean <- subset(dat, material == "Serum")
# Sort dat.clean
dat.clean <- dat.clean[order(dat.clean$feed),]
# Set names of variables
PREDICTOR <- c("day","feed")
OUTCOME <- "br_pct" #"bl_ratio"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 6 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 12 0.292 0.396 0.357 0.033 0.01
## 2 d08 LF 12 0.312 0.385 0.343 0.026 0.008
## 3 d16 HF 6 0.306 0.397 0.351 0.032 0.013
## 4 d16 LF 6 0.312 0.397 0.353 0.031 0.013
## 5 d21 HF 6 0.341 0.44 0.383 0.04 0.016
## 6 d21 LF 6 0.356 0.422 0.391 0.028 0.011
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym("l_pct"), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 6 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 12 0.604 0.708 0.643 0.033 0.01
## 2 d08 LF 12 0.615 0.688 0.657 0.026 0.008
## 3 d16 HF 6 0.603 0.694 0.649 0.032 0.013
## 4 d16 LF 6 0.603 0.688 0.647 0.031 0.013
## 5 d21 HF 6 0.56 0.659 0.617 0.04 0.016
## 6 d21 LF 6 0.578 0.644 0.609 0.028 0.011
# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## [1] feed day id sample_name rat_name
## [6] sample_org rat_org type material df
## [11] batch_no notes org_conc sample_conc_ug pfos_t_amt
## [16] pfos_b_amt pfos_l_amt bl_ratio dayfeed matfeed
## [21] br_pct l_pct is.outlier is.extreme
## <0 rækker> (eller 0-længde row.names)
# Check normality
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.976 0.442
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 5 42 0.380 0.860
This shows that data has two outlier, is normally distribution and has equal variance. Therefore we can test the data with a one-way ANOVA test with Tukey’s honest significance test.
7.2.1.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 day 2 42 6.217 0.004 * 0.228
## 2 feed 1 42 0.254 0.617 0.006
## 3 day:feed 2 42 0.582 0.563 0.027
Perform posthoc test
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 19 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 day d08 d16 0 0.00172 -0.0252 0.0286 0.987
## 2 day d08 d21 0 0.0373 0.0104 0.0642 0.00449
## 3 day d16 d21 0 0.0356 0.00456 0.0666 0.0213
## 4 feed HF LF 0 -0.00455 -0.0228 0.0137 0.617
## 5 day:feed d08:HF d16:HF 0 -0.00633 -0.0530 0.0404 0.999
## 6 day:feed d08:HF d21:HF 0 0.0263 -0.0204 0.0730 0.551
## 7 day:feed d08:HF d08:LF 0 -0.0141 -0.0522 0.0241 0.878
## 8 day:feed d08:HF d16:LF 0 -0.00430 -0.0510 0.0424 1
## 9 day:feed d08:HF d21:LF 0 0.0342 -0.0125 0.0809 0.265
## 10 day:feed d16:HF d21:HF 0 0.0327 -0.0213 0.0866 0.472
## 11 day:feed d16:HF d08:LF 0 -0.00775 -0.0545 0.0390 0.996
## 12 day:feed d16:HF d16:LF 0 0.00203 -0.0519 0.0560 1
## 13 day:feed d16:HF d21:LF 0 0.0406 -0.0134 0.0945 0.239
## 14 day:feed d21:HF d08:LF 0 -0.0404 -0.0871 0.00631 0.124
## 15 day:feed d21:HF d16:LF 0 -0.0306 -0.0846 0.0233 0.543
## 16 day:feed d21:HF d21:LF 0 0.00791 -0.0460 0.0618 0.998
## 17 day:feed d08:LF d16:LF 0 0.00977 -0.0369 0.0565 0.989
## 18 day:feed d08:LF d21:LF 0 0.0483 0.00160 0.0950 0.0389
## 19 day:feed d16:LF d21:LF 0 0.0385 -0.0154 0.0925 0.291
## # ℹ 1 more variable: p.adj.signif <chr>
Significant impact is observed between Day 21 and the two other days. We will plot this as a nested analysis with t-test and ANOVA with Tukey’s HSD on the inner variable and the outer variable.
7.2.1.3 Create figure
## Pairwise comparison for inner variable: day
stat.in <- dat.clean %>%
group_by(day) %>%
t_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 3 × 18
## day estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 d08 0.0141 0.357 0.343 br_pct HF LF 12 12 1.15
## 2 d16 -0.00203 0.351 0.353 br_pct HF LF 6 6 -0.113
## 3 d21 -0.00791 0.383 0.391 br_pct HF LF 6 6 -0.400
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
anova_test(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges p.signif p.format
## 1 day 2 45 6.443 0.003 * 0.223 ** 0.003
pwc2 <- dat.clean %>%
tukey_hsd(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 3 × 10
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 day d08 d16 0 0.00172 -0.0246 0.0281 0.986
## 2 day d08 d21 0 0.0373 0.0110 0.0637 0.00362
## 3 day d16 d21 0 0.0356 0.00518 0.0660 0.0183
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "day", dodge = 0.8)
pwc2 <- pwc2 %>% add_xy_position(x = "day")
pwc2$y.position <- max(stat.in$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "day", y = OUTCOME,
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_color_manual(values = c("LF" = "black","HF" = "black")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_x_discrete(name = "Day", labels = c("d08" = "Day 8","d16" = "Day 16","d21" = "Day 21")) +
theme(axis.title.x = element_blank()) +
guides(color = "none")
if (OUTCOME == "bl_ratio") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, tip.length = 0, hide.ns = TRUE, y.position = c(0.82, 0.78)) +
scale_y_continuous(name = "Serum B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, tip.length = 0, hide.ns = TRUE, y.position = c(0.46, 0.44)) +
scale_y_continuous(name = "Serum br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.statsuppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_serum.pdf"), plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 100))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_serum.png"), plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 100))
# BETWEEN DIETS
## Pairwise comparison for inner variable: day
stat.in2 <- dat.clean %>%
group_by(feed) %>%
anova_test(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in2## # A tibble: 2 × 10
## feed Effect DFn DFd F p `p<.05` ges p.signif p.format
## * <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <dbl> <chr> <chr>
## 1 HF day 2 21 1.60 0.226 "" 0.132 ns 0.226
## 2 LF day 2 21 6.19 0.008 "*" 0.371 ** 0.008
pwc.in2 <- dat.clean %>%
group_by(feed) %>%
tukey_hsd(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc.in2## # A tibble: 6 × 11
## feed term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF day d08 d16 0 -0.00633 -0.0498 0.0371 0.929
## 2 HF day d08 d21 0 0.0263 -0.0171 0.0698 0.299
## 3 HF day d16 d21 0 0.0327 -0.0175 0.0829 0.252
## 4 LF day d08 d16 0 0.00977 -0.0252 0.0447 0.763
## 5 LF day d08 d21 0 0.0483 0.0134 0.0832 0.00599
## 6 LF day d16 d21 0 0.0385 -0.00181 0.0789 0.0629
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Pairwise comparison for outer variable
stat.out2 <- dat.clean %>%
t_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out2## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 0.00455 0.362 0.357 br_pct HF LF 24 24 0.459 0.649
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
pwc.in2 <- pwc.in2 %>% add_xy_position(x = "feed", dodge = 0.8)
stat.out2 <- stat.out2 %>% add_xy_position(x = "feed")
stat.out2$y.position <- max(pwc.in2$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "feed", y = OUTCOME,
fill = "feed",
color = "day",
shape = "day",
add = "jitter",
add.params = list(size = 1, position_jitterdodge(dodge.width = 0.8))) +
theme_pubr() +
scale_color_manual(values = params$COL_4BLACK) +#, name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_shape_manual(values = c("d08" = 19, "d12" = 1, "d16" = 17, "d21" = 2), name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_x_discrete(name = "Feed") +
theme(axis.title.x = element_blank()) +
guides(color = "none", fill = "none", shape = "none")
pif (OUTCOME == "bl_ratio") {
p.stat2 <- p + stat_pvalue_manual(pwc.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Serum B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat2 <- p + stat_pvalue_manual(pwc.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Serum br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.stat2suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_serum_feed.pdf"), plot = p.stat2, device = "pdf", dpi = 300, units = "mm", height = 80, width = 100))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_serum_feed.png"), plot = p.stat2, device = "png", dpi = 300, units = "mm", height = 80, width = 100))
p.serum1 <- p.stat
p.serum2 <- p.stat2
save(p.serum1, p.serum2, file = "plots/animal_data/pfos/serum_isomer.Rdata")
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())7.2.1.4 Conclusion
From BL-ratio of serum, we can see that no significant difference was observed between feed groups on sampling days. However, BL-ratio is significantly higher on Day 21 compared to Day 8 and Day 16.
7.2.2 Liver data
Investigation of bl-ratio in treatment groups in Liver tissue samples on Day 8 and Day 21.
7.2.2.1 Prepare data
# Load data
load("R_objects/pfos_isomer_data.Rdata")
# Subset
dat.clean <- subset(dat, material == "Liver")
# Sort dat.clean
dat.clean <- dat.clean[order(dat.clean$feed),]
# Set names of variables
PREDICTOR <- c("day","feed")
OUTCOME <- "br_pct" #"bl_ratio"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 4 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 6 0.254 0.334 0.3 0.036 0.015
## 2 d08 LF 6 0.165 0.329 0.222 0.069 0.028
## 3 d21 HF 6 0.248 0.355 0.296 0.04 0.016
## 4 d21 LF 6 0.181 0.413 0.271 0.087 0.036
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym("l_pct"), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 4 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 6 0.666 0.746 0.7 0.036 0.015
## 2 d08 LF 6 0.671 0.835 0.778 0.069 0.028
## 3 d21 HF 6 0.645 0.752 0.704 0.04 0.016
## 4 d21 LF 6 0.587 0.819 0.729 0.087 0.036
# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## [1] feed day id sample_name rat_name
## [6] sample_org rat_org type material df
## [11] batch_no notes org_conc sample_conc_ug pfos_t_amt
## [16] pfos_b_amt pfos_l_amt bl_ratio dayfeed matfeed
## [21] br_pct l_pct is.outlier is.extreme
## <0 rækker> (eller 0-længde row.names)
# Check normality
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.952 0.294
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 3 20 1.29 0.306
This shows that data has two outlier, is normally distribution and has equal variance. Therefore we can test the data with a one-way ANOVA test with Tukey’s honest significance test.
7.2.2.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 day 1 20 0.782 0.387 0.038
## 2 feed 1 20 4.172 0.054 0.173
## 3 day:feed 1 20 1.096 0.308 0.052
Perform posthoc test
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 8 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj p.adj.signif
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 day d08 d21 0 0.0223 -0.0303 0.0748 0.387 ns
## 2 feed HF LF 0 -0.0515 -0.104 0.00109 0.0545 ns
## 3 day:… d08:HF d21:HF 0 -0.00410 -0.104 0.0956 0.999 ns
## 4 day:… d08:HF d08:LF 0 -0.0778 -0.178 0.0219 0.162 ns
## 5 day:… d08:HF d21:LF 0 -0.0292 -0.129 0.0705 0.845 ns
## 6 day:… d21:HF d08:LF 0 -0.0737 -0.173 0.0260 0.197 ns
## 7 day:… d21:HF d21:LF 0 -0.0251 -0.125 0.0746 0.894 ns
## 8 day:… d08:LF d21:LF 0 0.0487 -0.0511 0.148 0.534 ns
Significant impact is observed for feed but no other factors. We will plot this as a nested analysis with pairwise t-tests on the inner variable and the outer variable.
7.2.2.3 Create figure
# BETWEEN DAYS
# Pairwise comparison for inner variable: day
stat.in <- dat.clean %>%
group_by(day) %>%
t_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## day estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 d08 0.0778 0.300 0.222 br_pct HF LF 6 6 2.46
## 2 d21 0.0251 0.296 0.271 br_pct HF LF 6 6 0.640
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
t_test(as.formula(paste0(OUTCOME," ~ day")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 -0.0223 0.261 0.283 br_pct d08 d21 12 12 -0.825 0.418
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "day", dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = "day")
stat.out$y.position <- max(stat.in$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "day", y = OUTCOME,
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_color_manual(values = c("LF" = "black","HF" = "black")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_x_discrete(name = "Day", labels = c("d08" = "Day 8","d16" = "Day 16","d21" = "Day 21")) +
theme(axis.title.x = element_blank()) +
guides(color = "none")
if (OUTCOME == "bl_ratio") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Liver B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red", y.position = 0.35) +
stat_pvalue_manual(stat.out, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Liver br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.statsuppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_liver.pdf"), plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 75))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_liver.png"), plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 75))
# BETWEEN DIETS
## Pairwise comparison for inner variable: day
stat.in2 <- dat.clean %>%
group_by(feed) %>%
t_test(as.formula(paste0(OUTCOME," ~ day")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in2## # A tibble: 2 × 18
## feed estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 HF 0.00410 0.300 0.296 br_pct d08 d21 6 6 0.189
## 2 LF -0.0487 0.222 0.271 br_pct d08 d21 6 6 -1.07
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out2 <- dat.clean %>%
t_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out2## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 0.0515 0.298 0.246 br_pct HF LF 12 12 2.05 0.0526
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in2 <- stat.in2 %>% add_xy_position(x = "feed", dodge = 0.8)
stat.out2 <- stat.out2 %>% add_xy_position(x = "feed")
stat.out2$y.position <- max(stat.in2$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "feed", y = OUTCOME,
fill = "feed",
color = "day",
shape = "day",
add = "jitter",
add.params = list(size = 1, position_jitterdodge(dodge.width = 0.8))) +
theme_pubr() +
scale_color_manual(values = params$COL_4BLACK) +#, name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_shape_manual(values = c("d08" = 19, "d12" = 1, "d16" = 17, "d21" = 2), name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_x_discrete(name = "Feed") +
theme(axis.title.x = element_blank()) +
guides(color = "none", fill = "none", shape = "none")
if (OUTCOME == "bl_ratio") {
p.stat2 <- p + stat_pvalue_manual(stat.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Liver B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat2 <- p + stat_pvalue_manual(stat.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE, y.position = 0.4) +
scale_y_continuous(name = "Liver br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.stat2suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_liver_feed.pdf"), plot = p.stat2, device = "pdf", dpi = 300, units = "mm", height = 80, width = 75))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_liver_feed.png"), plot = p.stat2, device = "png", dpi = 300, units = "mm", height = 80, width = 75))
p.liver1 <- p.stat
p.liver2 <- p.stat2
save(p.liver1, p.liver2, file = "plots/animal_data/pfos/liver_isomer.Rdata")
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())7.2.2.4 Conclusion
From BL-ratio of liver, we can see a significant higher ratio in the High fibre group was observed on Day 8, while no difference but similar tendency was observed on Day 21. There was no difference between days.
7.2.3 Brain data
Investigation of bl-ratio in treatment groups in Brain tissue samples on Day 8 and 21.
7.2.3.1 Prepare data
# Load data
load("R_objects/pfos_isomer_data.Rdata")
# Subset
dat.clean <- subset(dat, material == "Brain"& !id == 133) # & !id == 133
# Sort dat.clean
dat.clean <- dat.clean[order(dat.clean$feed),]
# Set names of variables
PREDICTOR <- c("day","feed")#c("treatment","pfos","van")
OUTCOME <- "br_pct" #"bl_ratio"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 4 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 4 0.131 0.161 0.144 0.014 0.007
## 2 d08 LF 5 0.113 0.169 0.138 0.022 0.01
## 3 d21 HF 5 0.14 0.273 0.197 0.051 0.023
## 4 d21 LF 6 0.149 0.279 0.187 0.047 0.019
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym("l_pct"), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 4 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 4 0.839 0.869 0.856 0.014 0.007
## 2 d08 LF 5 0.831 0.887 0.862 0.022 0.01
## 3 d21 HF 5 0.727 0.86 0.803 0.051 0.023
## 4 d21 LF 6 0.721 0.851 0.813 0.047 0.019
# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 1 × 24
## feed day id sample_name rat_name sample_org rat_org type material df
## <chr> <chr> <int> <chr> <chr> <chr> <chr> <chr> <chr> <int>
## 1 LF d21 114 R20Bd21 R20 R20B21 R20 samp… Brain 8000
## # ℹ 14 more variables: batch_no <int>, notes <chr>, org_conc <dbl>,
## # sample_conc_ug <dbl>, pfos_t_amt <dbl>, pfos_b_amt <dbl>, pfos_l_amt <dbl>,
## # bl_ratio <dbl>, dayfeed <chr>, matfeed <chr>, br_pct <dbl>, l_pct <dbl>,
## # is.outlier <lgl>, is.extreme <lgl>
# Check normality
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.904 0.0490
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 3 16 0.892 0.466
This shows that data has two outlier of which one is critical and has been excluded (id 133). Data is furthermore normally distribution and has equal variance. Therefore we can test the data with a one-way ANOVA test with Tukey’s honest significance test.
7.2.3.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 day 1 16 8.458 0.010 * 0.346000
## 2 feed 1 16 0.220 0.645 0.014000
## 3 day:feed 1 16 0.013 0.910 0.000827
Perform posthoc test
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 8 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj p.adj.signif
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 day d08 d21 0 0.0507 0.0138 0.0877 0.0102 *
## 2 feed HF LF 0 -0.00817 -0.0451 0.0287 0.645 ns
## 3 day:… d08:HF d21:HF 0 0.0529 -0.0215 0.127 0.217 ns
## 4 day:… d08:HF d08:LF 0 -0.00595 -0.0803 0.0684 0.996 ns
## 5 day:… d08:HF d21:LF 0 0.0429 -0.0287 0.114 0.349 ns
## 6 day:… d21:HF d08:LF 0 -0.0588 -0.129 0.0113 0.117 ns
## 7 day:… d21:HF d21:LF 0 -0.00999 -0.0771 0.0571 0.973 ns
## 8 day:… d08:LF d21:LF 0 0.0488 -0.0183 0.116 0.201 ns
Significant impact is observed for between days but no other factors. We will plot this as a nested analysis with pairwise t-tests on the inner variable and the outer variable.
7.2.3.3 Create figure
## Pairwise comparison for inner variable: day
stat.in <- dat.clean %>%
group_by(day) %>%
t_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## day estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 d08 0.00595 0.144 0.138 br_pct HF LF 4 5 0.476
## 2 d21 0.00999 0.197 0.187 br_pct HF LF 5 6 0.337
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
t_test(as.formula(paste0(OUTCOME," ~ day")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 -0.0507 0.141 0.192 br_p… d08 d21 9 11 -3.07 0.00663
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "day", dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = "day")
stat.out$y.position <- max(stat.in$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "day", y = OUTCOME,
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_color_manual(values = c("LF" = "black","HF" = "black")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_x_discrete(name = "Day", labels = c("d08" = "Day 8","d16" = "Day 16","d21" = "Day 21")) +
theme(axis.title.x = element_blank()) +
guides(color = "none")
if (OUTCOME == "bl_ratio") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Brain B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Brain br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.statsuppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_brain.pdf"), plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 75))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_brain.png"), plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 75))
# BETWEEN DIETS
## Pairwise comparison for inner variable: day
stat.in2 <- dat.clean %>%
group_by(feed) %>%
t_test(as.formula(paste0(OUTCOME," ~ day")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in2## # A tibble: 2 × 18
## feed estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 HF -0.0529 0.144 0.197 br_pct d08 d21 4 5 -2.00
## 2 LF -0.0488 0.138 0.187 br_pct d08 d21 5 6 -2.11
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out2 <- dat.clean %>%
t_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out2## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 0.00869 0.174 0.165 br_pct HF LF 9 11 0.428 0.674
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in2 <- stat.in2 %>% add_xy_position(x = "feed", dodge = 0.8)
stat.out2 <- stat.out2 %>% add_xy_position(x = "feed")
stat.out2$y.position <- max(stat.in2$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "feed", y = OUTCOME,
fill = "feed",
color = "day",
shape = "day",
add = "jitter",
add.params = list(size = 1, position_jitterdodge(dodge.width = 0.8))) +
theme_pubr() +
scale_color_manual(values = params$COL_4BLACK) +#, name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_shape_manual(values = c("d08" = 19, "d12" = 1, "d16" = 17, "d21" = 2), name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_x_discrete(name = "Feed") +
theme(axis.title.x = element_blank()) +
guides(color = "none", fill = "none", shape = "none")
if (OUTCOME == "bl_ratio") {
p.stat2 <- p + stat_pvalue_manual(stat.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Brain B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat2 <- p + stat_pvalue_manual(stat.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Brain br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.stat2suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_brain_feed.pdf"), plot = p.stat2, device = "pdf", dpi = 300, units = "mm", height = 80, width = 75))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_brain_feed.png"), plot = p.stat2, device = "png", dpi = 300, units = "mm", height = 80, width = 75))
p.brain1 <- p.stat
p.brain2 <- p.stat2
save(p.brain1, p.brain2, file = "plots/animal_data/pfos/brain_isomer.Rdata")
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())7.2.3.4 Conclusion
From BL-ratio of brain, we can see a significant higher ratio in samples on DAy 21 compared to Day 8, while no significant difference is seen between feeding groups.
7.3 EXCRETED MEASUREMENTS
7.3.1 Feces data
Investigation of bl-ratio in treatment groups in feces samples collected on Day 8, Day 12, Day 16 and Day 21.
7.3.1.1 Prepare data
# Load data
load("R_objects/pfos_isomer_data.Rdata")
# Subset
dat.clean <- subset(dat, material == "Feces" & !id == c(474))
# Sort dat.clean
dat.clean <- dat.clean[order(dat.clean$feed),]
# Set names of variables
PREDICTOR <- "dayfeed"#c("day","feed")
OUTCOME <- "br_pct" #"bl_ratio"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(c("day","feed")))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 8 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 12 0.15 0.212 0.193 0.016 0.005
## 2 d08 LF 12 0.174 0.211 0.194 0.01 0.003
## 3 d12 HF 6 0.201 0.235 0.217 0.011 0.005
## 4 d12 LF 6 0.171 0.235 0.208 0.024 0.01
## 5 d16 HF 6 0.195 0.243 0.214 0.016 0.006
## 6 d16 LF 6 0.163 0.205 0.191 0.015 0.006
## 7 d21 HF 5 0.2 0.246 0.219 0.017 0.008
## 8 d21 LF 6 0.203 0.25 0.226 0.019 0.008
dat.clean %>% group_by(across(all_of(c("day","feed")))) %>% get_summary_stats(!!sym("l_pct"), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 8 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 12 0.788 0.85 0.807 0.016 0.005
## 2 d08 LF 12 0.789 0.826 0.806 0.01 0.003
## 3 d12 HF 6 0.765 0.799 0.783 0.011 0.005
## 4 d12 LF 6 0.765 0.829 0.792 0.024 0.01
## 5 d16 HF 6 0.757 0.805 0.786 0.016 0.006
## 6 d16 LF 6 0.795 0.837 0.809 0.015 0.006
## 7 d21 HF 5 0.754 0.8 0.781 0.017 0.008
## 8 d21 LF 6 0.75 0.797 0.774 0.019 0.008
# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 7 × 24
## dayfeed id sample_name rat_name sample_org rat_org type feed material
## <chr> <int> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 d08_HF 399 R45Fd08 R45 R45F8 R45 sample HF Feces
## 2 d12_HF 422 R44Fd12 R44 R42F12 R42 sample HF Feces
## 3 d12_HF 426 R48Fd12 R48 R48F12 R48 sample HF Feces
## 4 d16_HF 445 R43Fd16 R43 R41F16 R41 sample HF Feces
## 5 d16_HF 446 R44Fd16 R44 R42F16 R42 sample HF Feces
## 6 d16_LF 433 R19Fd16 R19 R19F16 R19 sample LF Feces
## 7 d21_HF 470 R44Fd21 R44 R42F21 R42 sample HF Feces
## # ℹ 15 more variables: day <chr>, df <int>, batch_no <int>, notes <chr>,
## # org_conc <dbl>, sample_conc_ug <dbl>, pfos_t_amt <dbl>, pfos_b_amt <dbl>,
## # pfos_l_amt <dbl>, bl_ratio <dbl>, matfeed <chr>, br_pct <dbl>, l_pct <dbl>,
## # is.outlier <lgl>, is.extreme <lgl>
# Check normality
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.975 0.259
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 7 51 1.12 0.363
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
This shows that data has seven outliers, is not normally distribution and has equal variance. Therefore we can test the data with a Kruskal-Wallis with posthoc Dunn’s test adjusted p-values.
7.3.1.2 Kruskal-Wallis test
Perform test
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 br_pct 59 28.2 7 0.000202 Kruskal-Wallis
Effect size
The eta squared, based on the H-statistic, can be used as the measure of the Kruskal-Wallis test effect size. The interpretation values commonly in published literature are: 0.01- < 0.06 (small effect), 0.06 - < 0.14 (moderate effect) and >= 0.14 (large effect).
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 br_pct 59 0.416 eta2[H] large
Post-hoc test if interaction is significant
A significant Kruskal-Wallis test is generally followed up by Dunn’s test to identify which groups are different. It’s also possible to use the Wilcoxon’s test to calculate pairwise comparisons between group levels with corrections for multiple testing.
## # A tibble: 28 × 9
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 br_pct d08_HF d08_LF 12 12 -0.131 0.896 0.968 ns
## 2 br_pct d08_HF d12_HF 12 6 2.93 0.00338 0.0190 *
## 3 br_pct d08_HF d12_LF 12 6 1.51 0.130 0.243 ns
## 4 br_pct d08_HF d16_HF 12 6 2.27 0.0232 0.0590 ns
## 5 br_pct d08_HF d16_LF 12 6 -0.116 0.907 0.968 ns
## 6 br_pct d08_HF d21_HF 12 5 2.66 0.00786 0.0291 *
## 7 br_pct d08_HF d21_LF 12 6 3.28 0.00104 0.0145 *
## 8 br_pct d08_LF d12_HF 12 6 3.04 0.00239 0.0190 *
## 9 br_pct d08_LF d12_LF 12 6 1.62 0.105 0.226 ns
## 10 br_pct d08_LF d16_HF 12 6 2.38 0.0174 0.0488 *
## # ℹ 18 more rows
Several groups show significant difference based of day and feed. We will plot this as a nested analysis with feed as the inner variable using a t-test and day as the outer variable using kruskal-wallis with posthoc Dunn’s test.
7.3.1.3 Create figure
## Pairwise comparison for inner variable: day
stat.in <- dat.clean %>%
group_by(day) %>%
wilcox_test(as.formula(paste0(OUTCOME," ~ feed"))) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj") %>%
add_xy_position(x = "day", dodge = 0.8) %>%
p_format("p.adj", accuracy = 0.0001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 4 × 16
## day .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 d08 br_pct HF LF 12 12 75 0.887 0.887 ns
## 2 d12 br_pct HF LF 6 6 22 0.589 0.883 ns
## 3 d16 br_pct HF LF 6 6 33 0.0152 0.0608 ns
## 4 d21 br_pct HF LF 5 6 12 0.662 0.883 ns
## # ℹ 6 more variables: y.position <dbl>, groups <named list>, x <dbl>,
## # xmin <dbl>, xmax <dbl>, p.adj.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
kruskal_test(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 8
## .y. n statistic df p method p.signif p.format
## * <chr> <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 br_pct 59 22.3 3 0.0000574 Kruskal-Wallis **** <0.001
pwc2 <- dat.clean %>%
dunn_test(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 6 × 10
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 br_pct d08 d12 24 12 3.22 0.00129 0.00645 **
## 2 br_pct d08 d16 24 12 1.60 0.110 0.330 ns
## 3 br_pct d08 d21 24 11 4.30 0.0000174 0.000104 ***
## 4 br_pct d12 d16 12 12 -1.40 0.161 0.330 ns
## 5 br_pct d12 d21 12 11 1.02 0.307 0.330 ns
## 6 br_pct d16 d21 12 11 2.39 0.0167 0.0668 ns
## # ℹ 1 more variable: p.adj.format <chr>
## Calculate positions statistics on plot
pwc2 <- pwc2 %>% add_xy_position(x = "day")
pwc2$y.position <- max(stat.in$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "day", y = OUTCOME,
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_color_manual(values = c("LF" = "black","HF" = "black")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_x_discrete(name = "Day", labels = c("d08" = "Day 8","d12" = "Day 12","d16" = "Day 16","d21" = "Day 21")) +
theme(axis.title.x = element_blank()) +
guides(color = "none")
if (OUTCOME == "bl_ratio") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, tip.length = 0, hide.ns = TRUE, y.position = c(0.33, 0.34)) +
scale_y_continuous(name = "Faeces B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, tip.length = 0, hide.ns = TRUE, y.position = c(0.26, 0.27)) +
scale_y_continuous(name = "Faeces br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.statsuppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_feces.pdf"), plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 125))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_feces.png"), plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 125))
# BETWEEN DIETS
## Pairwise comparison for inner variable: day
stat.in2 <- dat.clean %>%
group_by(feed) %>%
kruskal_test(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in2## # A tibble: 2 × 9
## feed .y. n statistic df p method p.signif p.format
## * <chr> <chr> <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 HF br_pct 29 15.0 3 0.00184 Kruskal-Wallis ** 0.0018
## 2 LF br_pct 30 11.6 3 0.00882 Kruskal-Wallis ** 0.0088
pwc.in2 <- dat.clean %>%
group_by(feed) %>%
dunn_test(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc.in2## # A tibble: 12 × 11
## feed .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 HF br_pct d08 d12 12 6 3.19 0.00142 0.00852 **
## 2 HF br_pct d08 d16 12 6 2.25 0.0244 0.0975 ns
## 3 HF br_pct d08 d21 12 5 2.93 0.00338 0.0169 *
## 4 HF br_pct d12 d16 6 6 -0.814 0.416 1 ns
## 5 HF br_pct d12 d21 6 5 -0.0582 0.954 1 ns
## 6 HF br_pct d16 d21 6 5 0.718 0.473 1 ns
## 7 LF br_pct d08 d12 12 6 1.33 0.185 0.555 ns
## 8 LF br_pct d08 d16 12 6 0.0379 0.970 0.970 ns
## 9 LF br_pct d08 d21 12 6 3.18 0.00147 0.00882 **
## 10 LF br_pct d12 d16 6 6 -1.11 0.265 0.555 ns
## 11 LF br_pct d12 d21 6 6 1.61 0.108 0.432 ns
## 12 LF br_pct d16 d21 6 6 2.72 0.00650 0.0325 *
## # ℹ 1 more variable: p.adj.format <chr>
## Pairwise comparison for outer variable
stat.out2 <- dat.clean %>%
wilcox_test(as.formula(paste0(OUTCOME," ~ feed"))) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj") %>%
add_xy_position(x = "day", dodge = 0.8) %>%
p_format("p.adj", accuracy = 0.0001, trailing.zero = TRUE, new.col = TRUE)
stat.out2## # A tibble: 1 × 14
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif y.position
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr> <dbl>
## 1 br_pct HF LF 29 30 520 0.202 0.202 ns 0.250
## # ℹ 4 more variables: groups <named list>, xmin <dbl>, xmax <dbl>,
## # p.adj.format <chr>
## Calculate positions statistics on plot
pwc.in2 <- pwc.in2 %>% add_xy_position(x = "feed", dodge = 0.8)
# Create plot
p <- ggboxplot(dat.clean, x = "feed", y = OUTCOME,
fill = "feed",
color = "day",
shape = "day",
add = "jitter",
add.params = list(size = 1, position_jitterdodge(dodge.width = 0.8))) +
theme_pubr() +
scale_color_manual(values = params$COL_4BLACK) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_shape_manual(values = c("d08" = 19, "d12" = 1, "d16" = 17, "d21" = 2), name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_x_discrete(name = "Feed") +
theme(axis.title.x = element_blank()) +
guides(color = "none", fill = "none", shape = "none")
if (OUTCOME == "bl_ratio") {
p.stat2 <- p + stat_pvalue_manual(pwc.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Faeces B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat2 <- p + stat_pvalue_manual(pwc.in2, tip.length = 0, hide.ns = TRUE, color = "red", y.position = c(0.245,0.255,0.255,0.265)) +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Faeces br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.stat2suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_faeces_feed.pdf"), plot = p.stat2, device = "pdf", dpi = 300, units = "mm", height = 80, width = 125))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_faeces_feed.png"), plot = p.stat2, device = "png", dpi = 300, units = "mm", height = 80, width = 125))
p.faeces1 <- p.stat
p.faeces2 <- p.stat2
save(p.faeces1, p.faeces2, file = "plots/animal_data/pfos/faeces_isomer.Rdata")
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())7.3.1.4 Conclusion
From BL-ratio of feces, we can see that a significant difference was observed between Day 8 and Day 21, as well as between feed groups on day 16. Results indicate that BL-ratio increase over time for feces excreted PFOS.
7.3.2 Cecum data
Investigation of bl-ratio in treatment groups in caecal content samples on Day 8 and Day 21.
7.3.2.1 Prepare data
# Load data
load("R_objects/pfos_isomer_data.Rdata")
# Subset
dat.clean <- subset(dat, material == "Cecum") # & !id == 133
# Sort dat.clean
dat.clean <- dat.clean[order(dat.clean$feed),]
# Set names of variables
PREDICTOR <- "dayfeed"#c("day","feed")
OUTCOME <- "br_pct" #"bl_ratio"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(c("day","feed")))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 4 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 6 0.187 0.221 0.201 0.012 0.005
## 2 d08 LF 6 0.171 0.202 0.186 0.014 0.006
## 3 d21 HF 6 0.179 0.222 0.195 0.015 0.006
## 4 d21 LF 6 0.124 0.219 0.176 0.035 0.014
dat.clean %>% group_by(across(all_of(c("day","feed")))) %>% get_summary_stats(!!sym("l_pct"), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 4 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 6 0.779 0.813 0.799 0.012 0.005
## 2 d08 LF 6 0.798 0.829 0.814 0.014 0.006
## 3 d21 HF 6 0.778 0.821 0.805 0.015 0.006
## 4 d21 LF 6 0.781 0.876 0.824 0.035 0.014
# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 2 × 24
## dayfeed id sample_name rat_name sample_org rat_org type feed material
## <chr> <int> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 d08_HF 333 R41Cd08 R41 R43C8 R43 sample HF Cecum
## 2 d21_HF 332 R44Cd21 R44 R42C21 R42 sample HF Cecum
## # ℹ 15 more variables: day <chr>, df <int>, batch_no <int>, notes <chr>,
## # org_conc <dbl>, sample_conc_ug <dbl>, pfos_t_amt <dbl>, pfos_b_amt <dbl>,
## # pfos_l_amt <dbl>, bl_ratio <dbl>, matfeed <chr>, br_pct <dbl>, l_pct <dbl>,
## # is.outlier <lgl>, is.extreme <lgl>
# Check normality
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.954 0.334
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 3 20 3.39 0.0381
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
This shows that data has no outlier, normal distribution, but not equal variance. Therefore we can test the data with a Welch ANOVA test with Games Howell test.
7.3.2.2 Welch ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## # A tibble: 1 × 7
## .y. n statistic DFn DFd p method
## * <chr> <int> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 br_pct 24 1.55 3 10.8 0.257 Welch ANOVA
Perform posthoc test
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 6 × 8
## .y. group1 group2 estimate conf.low conf.high p.adj p.adj.signif
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 br_pct d08_HF d08_LF -0.0143 -0.0374 0.00870 0.284 ns
## 2 br_pct d08_HF d21_HF -0.00588 -0.0305 0.0188 0.879 ns
## 3 br_pct d08_HF d21_LF -0.0242 -0.0756 0.0272 0.436 ns
## 4 br_pct d08_LF d21_HF 0.00845 -0.0177 0.0346 0.758 ns
## 5 br_pct d08_LF d21_LF -0.00985 -0.0613 0.0416 0.914 ns
## 6 br_pct d21_HF d21_LF -0.0183 -0.0698 0.0332 0.657 ns
No significant impact is observed. As data was normally distributed we will plot this as a nested analysis with pairwise t-tests on the inner variable and the outer variable.
7.3.2.3 Create figure
## Pairwise comparison for inner variable: day
stat.in <- dat.clean %>%
group_by(day) %>%
t_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 2 × 18
## day estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 d08 0.0143 0.201 0.186 br_pct HF LF 6 6 1.91
## 2 d21 0.0183 0.195 0.176 br_pct HF LF 6 6 1.18
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
t_test(as.formula(paste0(OUTCOME," ~ day")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 0.00787 0.193 0.186 br_pct d08 d21 12 12 0.881 0.391
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "day", dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = "day")
stat.out$y.position <- max(stat.in$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "day", y = OUTCOME,
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_color_manual(values = c("LF" = "black","HF" = "black")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_x_discrete(name = "Day", labels = c("d08" = "Day 8","d16" = "Day 16","d21" = "Day 21")) +
theme(axis.title.x = element_blank()) +
guides(color = "none")
if (OUTCOME == "bl_ratio") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Caecal B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Caecal br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.statsuppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_cecum.pdf"), plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 75))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_cecum.png"), plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 75))
# BETWEEN DIETS
## Pairwise comparison for inner variable: day
stat.in2 <- dat.clean %>%
group_by(feed) %>%
t_test(as.formula(paste0(OUTCOME," ~ day")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in2## # A tibble: 2 × 18
## feed estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 HF 0.00588 0.201 0.195 br_pct d08 d21 6 6 0.739
## 2 LF 0.00985 0.186 0.176 br_pct d08 d21 6 6 0.645
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out2 <- dat.clean %>%
t_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out2## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 0.0163 0.198 0.181 br_pct HF LF 12 12 1.94 0.0691
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
stat.in2 <- stat.in2 %>% add_xy_position(x = "feed", dodge = 0.8)
stat.out2 <- stat.out2 %>% add_xy_position(x = "feed")
stat.out2$y.position <- max(stat.in2$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "feed", y = OUTCOME,
fill = "feed",
color = "day",
shape = "day",
add = "jitter",
add.params = list(size = 1, position_jitterdodge(dodge.width = 0.8))) +
theme_pubr() +
scale_color_manual(values = params$COL_4BLACK) +#, name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_shape_manual(values = c("d08" = 19, "d12" = 1, "d16" = 17, "d21" = 2), name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_x_discrete(name = "Feed") +
theme(axis.title.x = element_blank()) +
guides(color = "none", fill = "none", shape = "none")
if (OUTCOME == "bl_ratio") {
p.stat2 <- p + stat_pvalue_manual(stat.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Caecal B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat2 <- p + stat_pvalue_manual(stat.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Caecal br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.stat2suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_cecum_feed.pdf"), plot = p.stat2, device = "pdf", dpi = 300, units = "mm", height = 80, width = 75))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_cecum_feed.png"), plot = p.stat2, device = "png", dpi = 300, units = "mm", height = 80, width = 75))
p.caecum1 <- p.stat
p.caecum2 <- p.stat2
save(p.caecum1, p.caecum2, file = "plots/animal_data/pfos/caecum_isomer.Rdata")
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())7.3.2.4 Conclusion
From BL-ratio of caecal content, we see no significant difference in either day or feed groups.
7.3.3 Urine data
Investigation of bl-ratio in treatment groups in urine samples collected on Day 8, Day 16 and Day 21.
7.3.3.1 Prepare data
# Load data
load("R_objects/pfos_isomer_data.Rdata")
# Subset
dat.clean <- subset(dat, material == "Urine")# & !id == c(474))
# Sort dat.clean
dat.clean <- dat.clean[order(dat.clean$feed),]
# Set names of variables
PREDICTOR <- c("day","feed")
OUTCOME <- "br_pct" #"bl_ratio"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 6 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 12 0.526 0.633 0.574 0.036 0.01
## 2 d08 LF 11 0.457 0.596 0.531 0.044 0.013
## 3 d16 HF 6 0.454 0.494 0.477 0.017 0.007
## 4 d16 LF 6 0.36 0.479 0.433 0.044 0.018
## 5 d21 HF 6 0.476 0.58 0.526 0.034 0.014
## 6 d21 LF 6 0.431 0.54 0.495 0.042 0.017
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym("l_pct"), type = "full") %>% select("day","feed","n","min","max","mean","sd","se")## # A tibble: 6 × 8
## day feed n min max mean sd se
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d08 HF 12 0.367 0.474 0.426 0.036 0.01
## 2 d08 LF 11 0.404 0.543 0.469 0.044 0.013
## 3 d16 HF 6 0.506 0.546 0.523 0.017 0.007
## 4 d16 LF 6 0.521 0.64 0.567 0.044 0.018
## 5 d21 HF 6 0.42 0.524 0.474 0.034 0.014
## 6 d21 LF 6 0.46 0.569 0.505 0.042 0.017
# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 2 × 24
## feed day id sample_name rat_name sample_org rat_org type material df
## <chr> <chr> <int> <chr> <chr> <chr> <chr> <chr> <chr> <int>
## 1 HF d21 288 R46Ud21 R46 R46U21 R46 samp… Urine 400
## 2 HF d21 289 R47Ud21 R47 R47U21 R47 samp… Urine 400
## # ℹ 14 more variables: batch_no <int>, notes <chr>, org_conc <dbl>,
## # sample_conc_ug <dbl>, pfos_t_amt <dbl>, pfos_b_amt <dbl>, pfos_l_amt <dbl>,
## # bl_ratio <dbl>, dayfeed <chr>, matfeed <chr>, br_pct <dbl>, l_pct <dbl>,
## # is.outlier <lgl>, is.extreme <lgl>
# Check normality
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.975 0.416
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 5 41 0.674 0.646
This shows that data has one none-critical outlier, is normally distribution and has equal variance. Therefore we can test the data with a one-way ANOVA test with Tukey’s honest significance test.
7.3.3.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 day 2 41 26.099 4.89e-08 * 0.560
## 2 feed 1 41 12.888 8.76e-04 * 0.239
## 3 day:feed 2 41 0.100 9.05e-01 0.005
Perform posthoc test
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 19 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 day d08 d16 0 -0.0984 -0.131 -0.0654 0.0000000214
## 2 day d08 d21 0 -0.0431 -0.0761 -0.0102 0.00771
## 3 day d16 d21 0 0.0552 0.0175 0.0930 0.00273
## 4 feed HF LF 0 -0.0399 -0.0623 -0.0174 0.000878
## 5 day:feed d08:HF d16:HF 0 -0.0968 -0.154 -0.0399 0.000118
## 6 day:feed d08:HF d21:HF 0 -0.0476 -0.105 0.00924 0.147
## 7 day:feed d08:HF d08:LF 0 -0.0423 -0.0898 0.00514 0.105
## 8 day:feed d08:HF d16:LF 0 -0.140 -0.197 -0.0835 0.0000000711
## 9 day:feed d08:HF d21:LF 0 -0.0791 -0.136 -0.0222 0.00208
## 10 day:feed d16:HF d21:HF 0 0.0492 -0.0165 0.115 0.243
## 11 day:feed d16:HF d08:LF 0 0.0545 -0.00326 0.112 0.0742
## 12 day:feed d16:HF d16:LF 0 -0.0436 -0.109 0.0221 0.369
## 13 day:feed d16:HF d21:LF 0 0.0177 -0.0480 0.0834 0.965
## 14 day:feed d21:HF d08:LF 0 0.00530 -0.0524 0.0630 1
## 15 day:feed d21:HF d16:LF 0 -0.0928 -0.158 -0.0271 0.00172
## 16 day:feed d21:HF d21:LF 0 -0.0315 -0.0971 0.0342 0.708
## 17 day:feed d08:LF d16:LF 0 -0.0981 -0.156 -0.0403 0.000122
## 18 day:feed d08:LF d21:LF 0 -0.0368 -0.0945 0.0210 0.415
## 19 day:feed d16:LF d21:LF 0 0.0613 -0.00437 0.127 0.0795
## # ℹ 1 more variable: p.adj.signif <chr>
Significant impact is observed on both day and feed. We will plot this as a nested analysis with t-test and ANOVA with Tukey’s HSD on the inner variable and the outer variable.
7.3.3.3 Create figure
## Pairwise comparison for inner variable: day
stat.in <- dat.clean %>%
group_by(day) %>%
t_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 3 × 18
## day estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 d08 0.0423 0.574 0.531 br_pct HF LF 12 11 2.53
## 2 d16 0.0436 0.477 0.433 br_pct HF LF 6 6 2.28
## 3 d21 0.0315 0.526 0.495 br_pct HF LF 6 6 1.42
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
anova_test(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges p.signif p.format
## 1 day 2 44 21.641 2.85e-07 * 0.496 **** <0.001
pwc2 <- dat.clean %>%
tukey_hsd(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 3 × 10
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 day d08 d16 0 -0.0984 -0.135 -0.0619 0.000000158
## 2 day d08 d21 0 -0.0431 -0.0796 -0.00667 0.017
## 3 day d16 d21 0 0.0552 0.0135 0.0970 0.00694
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "day", dodge = 0.8)
pwc2 <- pwc2 %>% add_xy_position(x = "day")
pwc2$y.position <- max(stat.in$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "day", y = OUTCOME,
fill = "feed",
color = "feed",
add = "jitter",
add.params = list(size = 1)) +
theme_pubr(legend = "top") +
scale_color_manual(values = c("LF" = "black","HF" = "black")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_x_discrete(name = "Day", labels = c("d08" = "Day 8","d16" = "Day 16","d21" = "Day 21")) +
theme(axis.title.x = element_blank()) +
guides(color = "none")
if (OUTCOME == "bl_ratio") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, tip.length = 0, hide.ns = TRUE, y.position = c(1.95, 2.05, 1.85)) +
scale_y_continuous(name = "Urine B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, tip.length = 0, hide.ns = TRUE, y.position = c(0.67, 0.69, 0.65)) +
scale_y_continuous(name = "Urine br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.statsuppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_urine.pdf"), plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 100))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_urine.png"), plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 100))
# BETWEEN DIETS
## Pairwise comparison for inner variable: day
stat.in2 <- dat.clean %>%
group_by(feed) %>%
anova_test(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in2## # A tibble: 2 × 10
## feed Effect DFn DFd F p `p<.05` ges p.signif p.format
## * <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <dbl> <chr> <chr>
## 1 HF day 2 21 18.5 0.0000229 * 0.639 **** <0.001
## 2 LF day 2 20 9.94 0.001 * 0.499 *** 0.001
pwc.in2 <- dat.clean %>%
group_by(feed) %>%
tukey_hsd(as.formula(paste0(OUTCOME," ~ day"))) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc.in2## # A tibble: 6 × 11
## feed term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF day d08 d16 0 -0.0968 -0.137 -0.0562 0.0000168
## 2 HF day d08 d21 0 -0.0476 -0.0883 -0.00701 0.0198
## 3 HF day d16 d21 0 0.0492 0.00226 0.0961 0.0389
## 4 LF day d08 d16 0 -0.0981 -0.154 -0.0424 0.000677
## 5 LF day d08 d21 0 -0.0368 -0.0924 0.0189 0.241
## 6 LF day d16 d21 0 0.0613 -0.00200 0.125 0.0588
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Pairwise comparison for outer variable
stat.out2 <- dat.clean %>%
t_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out2## # A tibble: 1 × 17
## estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic p
## * <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl> <dbl>
## 1 0.0414 0.538 0.496 br_pct HF LF 24 23 2.59 0.013
## # ℹ 7 more variables: df <dbl>, conf.low <dbl>, conf.high <dbl>, method <chr>,
## # alternative <chr>, p.signif <chr>, p.format <chr>
## Calculate positions statistics on plot
pwc.in2 <- pwc.in2 %>% add_xy_position(x = "feed", dodge = 0.8)
stat.out2 <- stat.out2 %>% add_xy_position(x = "feed")
stat.out2$y.position <- max(pwc.in2$y.position)*1.1
# Create plot
p <- ggboxplot(dat.clean, x = "feed", y = OUTCOME,
fill = "feed",
color = "day",
shape = "day",
add = "jitter",
add.params = list(size = 1, position_jitterdodge(dodge.width = 0.8))) +
theme_pubr() +
scale_color_manual(values = params$COL_4BLACK) +#, name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
scale_shape_manual(values = c("d08" = 19, "d12" = 1, "d16" = 17, "d21" = 2), name = "Day", labels = c("d08" = "8", "d12" = "12", "d16" = "16","d21" = "21")) +
scale_x_discrete(name = "Feed") +
theme(axis.title.x = element_blank()) +
guides(color = "none", fill = "none", shape = "none")
if (OUTCOME == "bl_ratio") {
p.stat2 <- p + stat_pvalue_manual(pwc.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(name = "Urine B/L ratio")
} else if (OUTCOME == "br_pct") {
p.stat2 <- p + stat_pvalue_manual(pwc.in2, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out2, tip.length = 0, hide.ns = TRUE, y.position = 0.73) +
scale_y_continuous(name = "Urine br-PFOS %", labels = function(x) paste0(x*100, "%"))
}
p.stat2suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_urine_feed.pdf"), plot = p.stat2, device = "pdf", dpi = 300, units = "mm", height = 80, width = 100))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_urine_feed.png"), plot = p.stat2, device = "png", dpi = 300, units = "mm", height = 80, width = 100))
p.urine1 <- p.stat
p.urine2 <- p.stat2
save(p.urine1, p.urine2, file = "plots/animal_data/pfos/urine_isomer.Rdata")
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())7.3.3.4 Conclusion
From BL-ratio of urine, we can see significant differences between sampling days and a trend towards higher BL-ratio in HF animals on Day 8 and 16, while only being significant on Day 8. Interestingly, Day 16 is significantly lower than both Day 8 and 21, which correlates with a significantly higher total PFOS concentration on Day 16 in urine. Overall the BL-ratio is very high compared to other materials, including feces and caecal content, indicating that br-PFOS is more readily expelled through urine in comparison.
7.4 ALL DATA
7.4.1 Material test
7.4.1.1 Prepare test of “material” day 8
Here we aim to test differences in bl-ratio between systemic and excreted samples on Day 8 and 21. We exclude Day 12 and 16, as not all sample types were recorded on these days. Included in the samples presented here are spiked negative controls and solvent controls which all have had the same batch of PFOS added directly to the same before analysis. These controls reflect the batch proportion of l-PFOS to br-PFOS.
load("R_objects/pfos_isomer_data.Rdata")
# Subset
dat.clean <- subset(dat, !type %in% c("suspension"))
# Set names of variables
PREDICTOR <- "matfeed"
OUTCOME <- "br_pct" #"bl_ratio"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 13 × 5
## matfeed variable n mean sd
## <chr> <fct> <dbl> <dbl> <dbl>
## 1 Brain_HF br_pct 10 0.179 0.047
## 2 Brain_LF br_pct 11 0.165 0.044
## 3 Cecum_HF br_pct 12 0.198 0.013
## 4 Cecum_LF br_pct 12 0.181 0.026
## 5 Feces_HF br_pct 30 0.21 0.025
## 6 Feces_LF br_pct 30 0.202 0.02
## 7 Liver_HF br_pct 12 0.298 0.036
## 8 Liver_LF br_pct 12 0.246 0.079
## 9 Serum_HF br_pct 24 0.362 0.035
## 10 Serum_LF br_pct 24 0.357 0.033
## 11 Urine_HF br_pct 24 0.538 0.051
## 12 Urine_LF br_pct 23 0.496 0.058
## 13 posctrl_HF br_pct 9 0.102 0.011
# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 8 × 24
## matfeed id sample_name rat_name sample_org rat_org type feed material
## <chr> <int> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 Brain_LF 114 R20Bd21 R20 R20B21 R20 sample LF Brain
## 2 Cecum_LF 310 R20Cd21 R20 R20C21 R20 sample LF Cecum
## 3 Feces_HF 399 R45Fd08 R45 R45F8 R45 sample HF Feces
## 4 Feces_HF 470 R44Fd21 R44 R42F21 R42 sample HF Feces
## 5 Feces_HF 474 R48Fd21 R48 R48F21 R48 sample HF Feces
## 6 Feces_LF 433 R19Fd16 R19 R19F16 R19 sample LF Feces
## 7 Feces_LF 458 R20Fd21 R20 R20F21 R20 sample LF Feces
## 8 Feces_LF 460 R22Fd21 R22 R22F21 R22 sample LF Feces
## # ℹ 15 more variables: day <chr>, df <int>, batch_no <int>, notes <chr>,
## # org_conc <dbl>, sample_conc_ug <dbl>, pfos_t_amt <dbl>, pfos_b_amt <dbl>,
## # pfos_l_amt <dbl>, bl_ratio <dbl>, dayfeed <chr>, br_pct <dbl>, l_pct <dbl>,
## # is.outlier <lgl>, is.extreme <lgl>
# Check normality
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.974 0.000251
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 12 220 6.26 0.00000000172
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
This shows that data has two critical outliers, is not normally distribution and does not have equal variance. Therefore we can test the data with a Kruskal-Wallis with Dunn’s test adjusted p-values.
7.4.1.2 Kruskal-Wallis test
Perform test
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 br_pct 233 201. 12 1.84e-36 Kruskal-Wallis
Effect size
The eta squared, based on the H-statistic, can be used as the measure of the Kruskal-Wallis test effect size. The interpretation values commonly in published literature are: 0.01- < 0.06 (small effect), 0.06 - < 0.14 (moderate effect) and >= 0.14 (large effect).
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 br_pct 233 0.860 eta2[H] large
Post-hoc test if interaction is significant
A significant Kruskal-Wallis test is generally followed up by Dunn’s test to identify which groups are different. It’s also possible to use the Wilcoxon’s test to calculate pairwise comparisons between group levels with corrections for multiple testing.
## # A tibble: 78 × 9
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 br_pct Brain_HF Brain_LF 10 11 -0.560 5.76e-1 6.15e-1 ns
## 2 br_pct Brain_HF Cecum_HF 10 12 0.607 5.44e-1 6.01e-1 ns
## 3 br_pct Brain_HF Cecum_LF 10 12 0.0323 9.74e-1 9.74e-1 ns
## 4 br_pct Brain_HF Feces_HF 10 30 1.36 1.73e-1 2.29e-1 ns
## 5 br_pct Brain_HF Feces_LF 10 30 0.974 3.30e-1 3.97e-1 ns
## 6 br_pct Brain_HF Liver_HF 10 12 2.90 3.70e-3 7.60e-3 **
## 7 br_pct Brain_HF Liver_LF 10 12 1.53 1.25e-1 1.81e-1 ns
## 8 br_pct Brain_HF posctrl_HF 10 9 -1.43 1.53e-1 2.09e-1 ns
## 9 br_pct Brain_HF Serum_HF 10 24 4.42 1.00e-5 3.12e-5 ****
## 10 br_pct Brain_HF Serum_LF 10 24 4.34 1.43e-5 4.28e-5 ****
## # ℹ 68 more rows
Several groups show significant difference based of day and feed. We will plot this as a nested analysis with feed as the inner variable using a t-test and day as the outer variable using kruskal-wallis with posthoc Dunn’s test. Data from Day 8 and 21 are both included in analysis and plotted data in this analysis but with visually separate presentation.
7.4.1.3 Create figure
# Order the data
df_order <- c("posctrl","Brain","Liver","Serum","Cecum","Feces","Urine") #old: c("Serum","Liver","Brain","Feces","Cecum","Urine","posctrl")
dat.clean$material <- factor(as.character(dat.clean$material), levels = df_order)
dat.clean <- dat.clean[order(dat.clean$material),]
## Pairwise comparison for inner variable
stat.in <- dat.clean %>% subset(!material == "posctrl") %>%
group_by(material) %>%
wilcox_test(as.formula(paste0(OUTCOME," ~ feed")),
paired = FALSE) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 6 × 10
## material .y. group1 group2 n1 n2 statistic p p.signif p.format
## * <fct> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <chr> <chr>
## 1 Brain br_pct HF LF 10 11 64 0.557 ns 0.557
## 2 Liver br_pct HF LF 12 12 104 0.0684 ns 0.068
## 3 Serum br_pct HF LF 24 24 309 0.675 ns 0.675
## 4 Cecum br_pct HF LF 12 12 101 0.101 ns 0.101
## 5 Feces br_pct HF LF 30 30 550 0.142 ns 0.142
## 6 Urine br_pct HF LF 24 23 387 0.0177 * 0.018
## Pairwise comparison for outer variable
stat.out <- dat.clean %>%
kruskal_test(as.formula(paste0(OUTCOME," ~ material"))) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 1 × 8
## .y. n statistic df p method p.signif p.format
## * <chr> <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 br_pct 233 198. 6 5.43e-40 Kruskal-Wallis **** <0.001
pwc2 <- dat.clean %>%
dunn_test(as.formula(paste0(OUTCOME," ~ material"))) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 21 × 10
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 br_pct posctrl Brain 9 21 1.33 1.84e- 1 5.53e- 1 ns
## 2 br_pct posctrl Liver 9 24 4.11 3.94e- 5 4.73e- 4 ***
## 3 br_pct posctrl Serum 9 48 6.35 2.22e-10 3.55e- 9 ****
## 4 br_pct posctrl Cecum 9 24 2.03 4.22e- 2 1.73e- 1 ns
## 5 br_pct posctrl Feces 9 60 3.03 2.44e- 3 2.20e- 2 *
## 6 br_pct posctrl Urine 9 47 8.33 8.28e-17 1.49e-15 ****
## 7 br_pct Brain Liver 21 24 3.61 3.09e- 4 3.40e- 3 **
## 8 br_pct Brain Serum 21 48 6.79 1.13e-11 1.93e-10 ****
## 9 br_pct Brain Cecum 21 24 0.887 3.75e- 1 5.53e- 1 ns
## 10 br_pct Brain Feces 21 60 2.19 2.88e- 2 1.73e- 1 ns
## # ℹ 11 more rows
## # ℹ 1 more variable: p.adj.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "material", dodge = 0.8)
pwc2 <- pwc2 %>% add_xy_position(x = "material")
pwc2$y.position <- max(stat.in$y.position)*1.1
# Mean and SD
dat.sum <- dat.clean %>% group_by(across(all_of(c("material","feed")))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")
dat.sum$material <- factor(as.character(dat.sum$material), levels = df_order)
dat.sum <- dat.sum[order(dat.sum$material),]
# Create plot
p <- ggplot() +
geom_crossbar(data=dat.sum,
aes(x = material,y = mean, ymin = mean, ymax = mean, color = feed),
linewidth=0.1, width = .7,
position = position_dodge(width = 0.8)) +
geom_errorbar(data=dat.sum,
aes(x = material,y = mean, ymin = mean-sd, ymax = mean+sd, color = feed),
linewidth=0.1, width = .3,
position = position_dodge(width = 0.8)) +
geom_point(data=dat.clean,
mapping = aes(x=material, y=.data[[OUTCOME]], color=feed), size = 1,
position = position_jitterdodge(dodge.width = 0.8, jitter.width = 0.3)) +
scale_color_manual(values = params$COLFEED, name = "Feed") +
scale_x_discrete(labels = c("posctrl" = "Reference", "Feces" = "Faeces", "Cecum" = "Caecum"))
if (OUTCOME == "bl_ratio") {
p.stat <- p + stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red", y.position = c(0.8, 1.7)) +
stat_pvalue_manual(pwc2, label = "p.adj.signif", tip.length = 0, hide.ns = TRUE, y.position = c(1.1,1.2,1.3,2.2,2.5,1,2.1,2,2.4,1.9,2.3,1.8,2.15)) +
scale_y_continuous(name = "B/L ratio",expand = expansion(mult = c(0.01, 0.1)), limits = c(0.05,2.5), breaks = seq(0.00,2.5,0.25)) +
theme_pubr(legend = "left") +
theme(axis.title.x = element_blank(), legend.position = c(0.99, .3),
legend.justification = c("right", "top"),
legend.box.just = "left",
legend.margin = margin(4, 4, 4, 4)) +
guides(color = guide_legend(override.aes = list(shape = 15, size = 4, linetype = c(0,0))))
} else if (OUTCOME == "br_pct") {
p.stat <- p + stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red", y.position = 0.65) +
stat_pvalue_manual(pwc2, label = "p.adj.signif", tip.length = 0, hide.ns = TRUE, y.position = c(0.45,0.5,0.625,0.675, 0.475,0.525,0.7, 0.55,0.575,0.725, 0.6,0.65,0.75, 0.775, 0.8)) +
scale_y_continuous(name = " br-PFOS %", labels = function(x) paste0(x*100, "%"), limits = c(0,0.82), breaks = seq(0.00,0.82,0.2)) +
theme_pubr(legend = "left") +
theme(axis.title.x = element_blank(), legend.position = c(0.99, .3),
legend.justification = c("right", "top"),
legend.box.just = "left",
legend.margin = margin(4, 4, 4, 4)) +
guides(color = guide_legend(override.aes = list(shape = 15, size = 4, linetype = c(0,0))))
# Letter code for legend explanation (attempt same-as code)
letter <- data.frame(material = c("posctrl","Brain","Liver","Serum","Cecum","Feces","Urine"), sig = c("abe","abef","ef","d","abef","bcef","g"), y = c(0.17,0.32,0.47,0.5,0.3,0.35,0.74))
# Plot with letter explanation
p.letter <- p + stat_pvalue_manual(stat.in, label = "p.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
scale_y_continuous(name = " br-PFOS %", labels = function(x) paste0(x*100, "%"), limits = c(0,0.75), breaks = seq(0.00,0.75,0.1)) +
geom_text(data = letter, aes(x = material, y = y, label = sig, fontface = "bold.italic"), size = 4) +
theme_pubr(legend = "top") +
theme(axis.title.x = element_blank(),
legend.position = c(0.5, 1),
legend.justification = c("top"),
legend.direction = "horizontal",
legend.margin = margin(4, 4, 4, 4)) +
guides(color = guide_legend(override.aes = list(shape = 15, size = 4, linetype = c(0,0)))) +
scale_x_discrete(labels = c("posctrl" = "Reference\n(a)","Brain" = "Brain\n(b)","Liver" = "Liver\n(c)","Serum" = "Serum\n(d)", "Cecum" = "Caecum\n(e)", "Feces" = "Faeces\n(f)", "Urine" = "Urine\n(g)"))
}## Scale for x is already present.
## Adding another scale for x, which will replace the existing scale.
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_material.pdf"), plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 200))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_material.png"), plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 200))
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_material_letter.pdf"), plot = p.letter, device = "pdf", dpi = 300, units = "mm", height = 100, width = 200)) #250 before
suppressMessages(ggsave(filename = paste0("plots/animal_data/pfos/isomer_",OUTCOME,"_material_letter.png"), plot = p.letter, device = "png", dpi = 300, units = "mm", height = 100, width = 200))
p.mat_stat <- p.stat
p.mat_letter <- p.letter
save(p.mat_stat, p.mat_letter, file = "plots/animal_data/pfos/mat_isomer.Rdata")
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())7.4.1.4 Conclusion
Large significant differences observed between samples types (material), where all but cecum and brain were significantly higher than control samples. Among the systemic samples, the BL-ratio was highest in serum > liver > brain which interestingly correlated directly to the same order in total PFOS concentrations. Highest BL-ratio is observed in urine, suggesting that br-PFOS is more readily expelled by urine than by feces. Differences in feed show higher BL-ratio in HF in liver and urine samples, while no differences are observed in remaining sample types.
7.4.2 Combine plots
# Load rdata files with scfa plots
pfiles <- list.files(path = "plots/animal_data/pfos", pattern = "*isomer.Rdata", full.names = TRUE)
lapply(pfiles, load,.GlobalEnv)## [[1]]
## [1] "p.brain1" "p.brain2"
##
## [[2]]
## [1] "p.caecum1" "p.caecum2"
##
## [[3]]
## [1] "p.faeces1" "p.faeces2"
##
## [[4]]
## [1] "p.liver1" "p.liver2"
##
## [[5]]
## [1] "p.mat_stat" "p.mat_letter"
##
## [[6]]
## [1] "p.serum1" "p.serum2"
##
## [[7]]
## [1] "p.urine1" "p.urine2"
# Plot isomer plots per feed
p.all <- ggarrange(p.brain2,p.liver2,p.serum2,p.caecum2,p.faeces2,p.urine2,
ncol = 3, nrow = 2,
common.legend = TRUE,
legend = "top",
label.x = 0,
font.label = list(size = 24, face = "bold"),
labels = c("B","C","D","E","F","G"),
align = "hv")
p.all# Save graphics
ggsave(filename = "plots/animal_data/pfos/isomer_all.png", p.all, device = "png", dpi = 300, height = 160, width = 250, units = "mm")
ggsave(filename = "plots/animal_data/pfos/isomer_all.pdf", p.all, device = "pdf", dpi = 300, height = 160, width = 250, units = "mm")
# clear the environment and release memory
rm(list = ls(all.names = TRUE)) #will clear all objects includes hidden objects.
invisible(gc()) #free up memory and report the memory usage.8 SHORT-CHAIN FATTY ACIDS
Concentrations in mM were recorded from caecal water samples from caecal content collected from all animals (except R04) at dissection.
8.1 Prepare SCFA data
# Load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
dat.clean <- dat %>% select(rat_name, feed, treatment, feedtreat, dissection,
acetic, formic, propanoic, m2_propanoic, butanoic, m3_butanoic, pentanoic, hexanoic)# not included due to low sample count: m4_pentanoic, heptanoic,
# Subset data with NA
dat.clean <- subset(dat.clean, !dat.clean$rat_name == "R04") # Mostly <LOD - suspects error in sample handling
# Create SCFA table
row.names(dat.clean) <- dat.clean$rat_name
dat.SCFA <- dat.clean %>% select(acetic, formic, propanoic, m2_propanoic, butanoic, m3_butanoic, pentanoic, hexanoic)
dat.SCFA## acetic formic propanoic m2_propanoic butanoic m3_butanoic
## R01 7.341875 0.5368092 1.8222638 0.11458476 0.8987209 0.054977624
## R02 7.855208 0.0000000 2.2070656 0.10691220 1.3073081 0.059441549
## R03 5.146957 0.0000000 2.4561816 0.00000000 0.7532571 0.000000000
## R05 7.982690 0.0000000 2.0544536 0.00000000 1.1110579 0.196319793
## R06 8.776675 0.2176932 2.7126279 0.15528998 1.8636544 0.066751284
## R07 9.639725 0.0000000 2.6859899 0.14239121 1.7281461 0.061447497
## R08 9.078671 0.0000000 2.2318548 0.18339766 1.3368317 0.091758195
## R09 8.897958 0.0000000 2.5053508 0.18053536 1.8769926 0.089813034
## R10 8.474208 0.0000000 2.0948772 0.12049304 3.8161456 0.069922162
## R11 7.155427 0.0000000 2.2205310 0.17458153 1.2040138 0.095099852
## R12 7.616896 0.6456507 1.5972133 0.20695849 1.9141834 0.100049621
## R13 9.667622 0.5837262 1.5603675 0.07482866 1.5538837 0.000000000
## R14 9.115617 0.3122245 2.0621057 0.11677311 1.2724029 0.045396199
## R15 4.641313 0.0000000 1.7988561 0.11952145 1.3137417 0.000000000
## R16 6.693080 0.0000000 2.4530337 0.13023905 1.2864006 0.073027831
## R17 8.877980 0.0000000 2.2304256 0.13800313 1.3169297 0.000000000
## R18 8.862873 0.5053084 1.5964168 0.19264865 1.2247779 0.000000000
## R19 7.951609 0.8993531 1.8304303 0.13977563 2.1861283 0.061983538
## R20 4.896264 0.2832883 1.8612969 0.18828803 1.0282520 0.109074443
## R21 11.985676 0.9859684 2.9109754 0.18071705 3.0569397 0.064346567
## R22 5.833129 0.0000000 1.8684475 0.12256397 1.4143747 0.058381178
## R23 9.654142 0.3776905 2.4182053 0.22178789 1.8719020 0.081073913
## R24 7.269043 0.3158913 2.2975509 0.20146583 1.8965003 0.089134967
## R25 8.419374 0.0000000 2.9202104 0.06544546 5.2225577 0.054289225
## R26 9.665720 0.0000000 5.8420110 0.12858333 2.3644827 0.050600100
## R27 12.538374 0.0000000 4.2183282 0.00000000 3.6613416 0.022126931
## R28 10.856261 0.0000000 1.9168245 0.05987570 8.0273412 0.048581262
## R29 15.170864 0.0000000 4.5226069 0.05354928 5.6681538 0.043748015
## R30 13.344693 0.6733067 2.6888836 0.00000000 4.5156249 0.000000000
## R31 13.265482 0.2137461 5.1847575 0.00000000 3.0914315 0.041388678
## R32 13.353800 0.0000000 3.0404715 0.08925862 9.9168104 0.070912110
## R33 12.063924 0.0000000 2.5849463 0.11912504 8.4525493 0.077120881
## R34 22.272322 0.0000000 4.3954526 0.06873288 11.6715032 0.064804495
## R35 13.505658 0.0000000 3.8940381 0.00000000 3.9437064 0.035908872
## R36 10.876729 0.0000000 1.2645777 0.10764445 11.3094552 0.000000000
## R37 11.278974 0.0000000 1.7892070 0.00000000 10.3384594 0.025993469
## R38 9.753901 0.0000000 1.6376468 0.00000000 8.4755453 0.039117832
## R39 15.438630 0.0000000 2.3605013 0.00000000 7.9623058 0.000000000
## R40 4.035739 0.0000000 0.4303487 0.00000000 0.7893027 0.006379562
## R41 10.050717 0.0000000 3.1157795 0.00000000 8.9074275 0.086542332
## R42 11.070575 0.0000000 3.4034263 0.00000000 8.8724006 0.000000000
## R43 10.123028 0.0000000 2.3501190 0.13122850 7.7081915 0.110326575
## R44 12.980268 0.0000000 3.8181246 0.00000000 3.4227372 0.015590715
## R45 10.372582 0.0000000 1.8797750 0.15641959 7.9450705 0.111311094
## R46 11.491241 0.0000000 2.8512537 0.00000000 2.0516026 0.000000000
## R47 13.238087 0.0000000 2.3206747 0.09039197 9.4090312 0.000000000
## R48 11.613649 0.0000000 4.1687121 0.00000000 2.4192800 0.032778659
## pentanoic hexanoic
## R01 0.14404969 0.00000000
## R02 0.20677422 0.00000000
## R03 0.00000000 0.00000000
## R05 0.00000000 0.00000000
## R06 0.25712467 0.00000000
## R07 0.29442662 0.00000000
## R08 0.25882488 0.00000000
## R09 0.23754051 0.00000000
## R10 0.21271455 0.01006928
## R11 0.21340815 0.00000000
## R12 0.24892344 0.00000000
## R13 0.16003737 0.00000000
## R14 0.23624010 0.00000000
## R15 0.13625584 0.00000000
## R16 0.18270472 0.00000000
## R17 0.20608063 0.00000000
## R18 0.19895460 0.00000000
## R19 0.23389303 0.00000000
## R20 0.19827676 0.00000000
## R21 0.27670456 0.00000000
## R22 0.17901674 0.01240264
## R23 0.30114933 0.00000000
## R24 0.26399449 0.00000000
## R25 0.17542959 0.00000000
## R26 0.19197483 0.00000000
## R27 0.12854350 0.01802084
## R28 0.16177640 0.03430010
## R29 0.20207998 0.02867673
## R30 0.09025981 0.01102509
## R31 0.21254619 0.00000000
## R32 0.15988369 0.00000000
## R33 0.22606772 0.00000000
## R34 0.18259935 0.17746828
## R35 0.18351147 0.00000000
## R36 0.16723953 0.20377836
## R37 0.18224357 0.01777665
## R38 0.14979775 0.00000000
## R39 0.12749008 0.00000000
## R40 0.00000000 0.00000000
## R41 0.21484340 0.17024430
## R42 0.18989833 0.00000000
## R43 0.25556194 0.00000000
## R44 0.13723693 0.00000000
## R45 0.28516897 0.01934100
## R46 0.08847509 0.00000000
## R47 0.20498220 0.03455655
## R48 0.06619971 0.01806011
# Change all zeros to NA
dat.clean[dat.clean == 0] <- NA
# Summary samples in groups
tb <- dat.clean %>% group_by(across(all_of("feedtreat"))) %>% get_summary_stats(type = "mean_sd")
tb## # A tibble: 31 × 5
## feedtreat variable n mean sd
## <chr> <fct> <dbl> <dbl> <dbl>
## 1 HF_CTRL acetic 12 12.9 3.48
## 2 HF_CTRL formic 2 0.444 0.325
## 3 HF_CTRL propanoic 12 3.54 1.36
## 4 HF_CTRL m2_propanoic 8 0.087 0.029
## 5 HF_CTRL butanoic 12 6.49 3.26
## 6 HF_CTRL m3_butanoic 10 0.051 0.017
## 7 HF_CTRL pentanoic 12 0.173 0.037
## 8 HF_CTRL hexanoic 6 0.079 0.087
## 9 HF_PFOS acetic 12 11.0 2.72
## 10 HF_PFOS propanoic 12 2.51 1.04
## # ℹ 21 more rows
## Warning: There were 2 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `ci = abs(stats::qt(alpha/2, .data$n - 1) * .data$se)`.
## Caused by warning:
## ! There was 1 warning in `mutate()`.
## ℹ In argument: `ci = abs(stats::qt(alpha/2, .data$n - 1) * .data$se)`.
## Caused by warning in `stats::qt()`:
## ! NaNs produced
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
## # A tibble: 31 × 14
## feedtreat variable n min max median q1 q3 iqr mad mean
## <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF_CTRL acetic 12 8.42 22.3 12.9 10.9 13.4 2.52 2.12 12.9
## 2 HF_CTRL formic 2 0.214 0.673 0.444 0.329 0.558 0.23 0.341 0.444
## 3 HF_CTRL propano… 12 1.26 5.84 3.47 2.66 4.43 1.76 1.34 3.54
## 4 HF_CTRL m2_prop… 8 0.054 0.129 0.079 0.064 0.111 0.046 0.033 0.087
## 5 HF_CTRL butanoic 12 2.36 11.7 5.44 3.87 8.82 4.94 3.66 6.49
## 6 HF_CTRL m3_buta… 10 0.022 0.077 0.05 0.042 0.062 0.02 0.016 0.051
## 7 HF_CTRL pentano… 12 0.09 0.226 0.179 0.161 0.195 0.033 0.027 0.173
## 8 HF_CTRL hexanoic 6 0.011 0.204 0.031 0.021 0.142 0.121 0.025 0.079
## 9 HF_PFOS acetic 12 4.04 15.4 11.2 10.1 12.0 1.85 1.61 11.0
## 10 HF_PFOS propano… 12 0.43 4.17 2.36 1.86 3.19 1.33 0.952 2.51
## # ℹ 21 more rows
## # ℹ 3 more variables: sd <dbl>, se <dbl>, ci <dbl>
8.2 Concentration plots
8.2.1 Prepare conc. data
# Load data
load("R_objects/SCFA_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Prepare data for faceted concentrations plots
dat.conc <- dat.clean %>% pivot_longer(., cols = c(acetic, formic, propanoic, m2_propanoic, butanoic, m3_butanoic, pentanoic, hexanoic), names_to = "compound", values_to = "mM") %>% mutate("comp_name" = case_when(compound == "formic" ~ "Formate", compound == "acetic" ~ "Acetate", compound == "propanoic" ~ "Propionate", compound == "m2_propanoic" ~ "Isobutyrate", compound == "butanoic" ~ "Butyrate", compound == "m3_butanoic" ~ "Isovalerate",compound == "pentanoic" ~ "Valerate", compound == "m4_pentanoic" ~ "Isocaproate", compound == "hexanoic" ~ "Caproate", compound == "heptanoic" ~ "Enanthate"))
dat.conc <- subset(dat.conc, !is.na(mM))
# Set names of variables
PREDICTOR <- c("feedtreat","comp_name") #"matfeed"
OUTCOME <- "mM"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.conc %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 31 × 6
## feedtreat comp_name variable n mean sd
## <chr> <chr> <fct> <dbl> <dbl> <dbl>
## 1 HF_CTRL Acetate mM 12 12.9 3.48
## 2 HF_CTRL Butyrate mM 12 6.49 3.26
## 3 HF_CTRL Caproate mM 6 0.079 0.087
## 4 HF_CTRL Formate mM 2 0.444 0.325
## 5 HF_CTRL Isobutyrate mM 8 0.087 0.029
## 6 HF_CTRL Isovalerate mM 10 0.051 0.017
## 7 HF_CTRL Propionate mM 12 3.54 1.36
## 8 HF_CTRL Valerate mM 12 0.173 0.037
## 9 HF_PFOS Acetate mM 12 11.0 2.72
## 10 HF_PFOS Butyrate mM 12 6.52 3.34
## # ℹ 21 more rows
dat.conc %>% group_by(across(all_of(c("feedtreat","comp_name","dissection")))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 59 × 7
## feedtreat dissection comp_name variable n mean sd
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl>
## 1 HF_CTRL d08 Acetate mM 6 11.7 2.49
## 2 HF_CTRL d21 Acetate mM 6 14.2 4.07
## 3 HF_CTRL d08 Butyrate mM 6 4.91 1.93
## 4 HF_CTRL d21 Butyrate mM 6 8.06 3.71
## 5 HF_CTRL d08 Caproate mM 4 0.023 0.01
## 6 HF_CTRL d21 Caproate mM 2 0.191 0.019
## 7 HF_CTRL d08 Formate mM 1 0.673 NA
## 8 HF_CTRL d21 Formate mM 1 0.214 NA
## 9 HF_CTRL d08 Isobutyrate mM 4 0.077 0.035
## 10 HF_CTRL d21 Isobutyrate mM 4 0.096 0.022
## # ℹ 49 more rows
dat.conc %>% group_by(across(all_of(c("feedtreat","comp_name","dissection")))) %>% get_summary_stats(!!sym(OUTCOME), type = "full")## Warning: There were 5 warnings in `mutate()`.
## The first warning was:
## ℹ In argument: `ci = abs(stats::qt(alpha/2, .data$n - 1) * .data$se)`.
## Caused by warning:
## ! There was 1 warning in `mutate()`.
## ℹ In argument: `ci = abs(stats::qt(alpha/2, .data$n - 1) * .data$se)`.
## Caused by warning in `stats::qt()`:
## ! NaNs produced
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 4 remaining warnings.
## # A tibble: 59 × 16
## feedtreat dissection comp_name variable n min max median q1
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF_CTRL d08 Acetate mM 6 8.42 15.2 11.7 9.96
## 2 HF_CTRL d21 Acetate mM 6 10.9 22.3 13.3 12.4
## 3 HF_CTRL d08 Butyrate mM 6 2.36 8.03 4.87 3.88
## 4 HF_CTRL d21 Butyrate mM 6 3.09 11.7 9.18 5.07
## 5 HF_CTRL d08 Caproate mM 4 0.011 0.034 0.023 0.016
## 6 HF_CTRL d21 Caproate mM 2 0.177 0.204 0.191 0.184
## 7 HF_CTRL d08 Formate mM 1 0.673 0.673 0.673 0.673
## 8 HF_CTRL d21 Formate mM 1 0.214 0.214 0.214 0.214
## 9 HF_CTRL d08 Isobutyrate mM 4 0.054 0.129 0.063 0.058
## 10 HF_CTRL d21 Isobutyrate mM 4 0.069 0.119 0.098 0.084
## # ℹ 49 more rows
## # ℹ 7 more variables: q3 <dbl>, iqr <dbl>, mad <dbl>, mean <dbl>, sd <dbl>,
## # se <dbl>, ci <dbl>
# Test for outliers
dat.conc %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 10 × 10
## feedtreat comp_name rat_name feed treatment dissection compound mM
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <dbl>
## 1 HF_CTRL Acetate R34 HF CTRL d21 acetic 22.3
## 2 HF_CTRL Valerate R30 HF CTRL d08 pentanoic 0.0903
## 3 HF_PFOS Acetate R39 HF PFOS d08 acetic 15.4
## 4 HF_PFOS Acetate R40 HF PFOS d08 acetic 4.04
## 5 HF_PFOS Caproate R41 HF PFOS d08 hexanoic 0.170
## 6 LF_CTRL Acetate R03 LF CTRL d08 acetic 5.15
## 7 LF_CTRL Butyrate R10 LF CTRL d21 butanoic 3.82
## 8 LF_CTRL Isovalerate R05 LF CTRL d08 m3_butanoic 0.196
## 9 LF_CTRL Valerate R01 LF CTRL d08 pentanoic 0.144
## 10 LF_PFOS Butyrate R21 LF PFOS d21 butanoic 3.06
## # ℹ 2 more variables: is.outlier <lgl>, is.extreme <lgl>
# Check normality
# Build the linear model
model <- lm(FORMULA, data = dat.conc)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.740 1.23e-20
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 30 248 6.00 1.40e-16
This shows that data has ten outliers of which four are critical, it is not normally distribution and does not have equal variance, which is expected from the compiled SCFA data columns. Therefore we can test the data with a Kruskal-Wallis with Dunn’s test adjusted p-values, which will here be calculated per compound across feed and treatment groups presented in a faceted plot.
8.2.2 Create nested figure
# Order the data
df_order <- c("Formate","Acetate","Propionate","Isobutyrate","Butyrate","Isovalerate","Valerate","Caproate")
dat.conc$comp_name <- factor(as.character(dat.conc$comp_name), levels = df_order)
dat.conc <- dat.conc[order(dat.conc$comp_name),]
# Exclusion of Formate from statistical analysis, as pairwise analysis cannot be done on missing groups of data
dat.conc2 <- dat.conc %>% subset(!(comp_name %in% c("Formate")))
# Set variables for inner and outer analysis, and variable for facet
INNER.VAR <- "treatment"
OUTER.VAR <- "feed"
FACETVAR <- "comp_name"
# Statistics for facet by compound
stat.in <- dat.conc2 %>%
group_by(.data[[FACETVAR]],.data[[OUTER.VAR]]) %>%
wilcox_test(as.formula(paste("mM ~",INNER.VAR, sep = " ")), paired = FALSE) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj") %>%
p_format("p.adj", accuracy = 0.0001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 14 × 12
## feed comp_name .y. group1 group2 n1 n2 statistic p p.adj
## * <chr> <fct> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl>
## 1 HF Acetate mM CTRL PFOS 12 12 97 0.16 0.747
## 2 LF Acetate mM CTRL PFOS 11 12 64 0.928 1
## 3 HF Propionate mM CTRL PFOS 12 12 106 0.0519 0.594
## 4 LF Propionate mM CTRL PFOS 11 12 84 0.288 0.868
## 5 HF Isobutyrate mM CTRL PFOS 8 3 3 0.0848 0.594
## 6 LF Isobutyrate mM CTRL PFOS 9 12 52 0.917 1
## 7 HF Butyrate mM CTRL PFOS 12 12 74 0.932 1
## 8 LF Butyrate mM CTRL PFOS 11 12 59 0.695 1
## 9 HF Isovalerate mM CTRL PFOS 10 8 46 0.633 1
## 10 LF Isovalerate mM CTRL PFOS 10 8 49 0.46 1
## 11 HF Valerate mM CTRL PFOS 12 11 68 0.928 1
## 12 LF Valerate mM CTRL PFOS 9 12 69 0.31 0.868
## 13 HF Caproate mM CTRL PFOS 6 5 17 0.792 1
## 14 LF Caproate mM CTRL PFOS 1 1 0 1 1
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
stat.out <- dat.conc2 %>%
group_by(.data[[FACETVAR]]) %>%
wilcox_test(as.formula(paste("mM ~",OUTER.VAR, sep = " ")), paired = FALSE) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj") %>%
p_format("p.adj", accuracy = 0.0001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 7 × 11
## comp_name .y. group1 group2 n1 n2 statistic p p.adj
## * <fct> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl>
## 1 Acetate mM HF LF 24 23 506 0.000000076 2.66e-7
## 2 Propionate mM HF LF 24 23 409 0.00411 5.41e-3
## 3 Isobutyrate mM HF LF 11 21 35 0.000866 2.02e-3
## 4 Butyrate mM HF LF 24 23 520 0.0000000054 3.78e-8
## 5 Isovalerate mM HF LF 18 18 74 0.00464 5.41e-3
## 6 Valerate mM HF LF 23 21 116 0.00269 4.71e-3
## 7 Caproate mM HF LF 11 2 21 0.0513 5.13e-2
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = OUTER.VAR, dodge = 0.8)
stat.out <- stat.out %>% add_xy_position(x = OUTER.VAR)
stat.out$y.position <- c(24,6.2,0.24,13,0.21,0.32,0.21) #manual adjustment
# Create list of mean and sd for plotting
dat.sum <- dat.conc %>% group_by(across(all_of(c("comp_name","feedtreat")))) %>% get_summary_stats(!!sym("mM"), type = "mean_sd")
dat.sum <- dat.sum %>% mutate("feed" = case_when(grepl("HF_",feedtreat) ~ "HF",
grepl("LF_",feedtreat) ~ "LF"))
dat.lod <- data.frame("comp_name" = c("Formate","Acetate","Propionate","Isobutyrate","Butyrate","Isovalerate","Valerate","Isocaproate","Caproate","Enanthate"),
"LOD" = c(0.18,0.1,0.07,0.05,0.02,0.01,0.01,0.09,0.01,0.04))
dat.lod <- subset(dat.lod, dat.lod$comp_name %in% c("Formate","Acetate","Propionate","Isobutyrate","Butyrate","Isovalerate","Valerate","Caproate"))
# Order the data
dat.lod$comp_name <- factor(as.character(dat.lod$comp_name), levels = df_order)
dat.lod <- dat.lod[order(dat.lod$comp_name),]
# Plot
p <- ggplot() +
geom_hline(data = dat.lod, aes(yintercept = LOD), linetype = "dashed", color = "#666666") +
geom_crossbar(data=dat.sum,
aes(x = feed, y = mean, ymin = mean, ymax = mean, color = feedtreat),
linewidth=0.1, width = 0.7,
position = position_dodge(width = 0.8)) +
geom_errorbar(data=dat.sum,
aes(x = feed, y = mean, ymin = mean-sd, ymax = mean+sd, color = feedtreat),
linewidth=0.1, width = 0.3,
position = position_dodge(width = 0.8)) +
geom_jitter(data = dat.conc, aes(x = feed, y = mM, color = feedtreat, shape = dissection),
position = position_jitterdodge(jitter.width = 0.1, dodge.width = 0.8)) +
scale_x_discrete(name = "Group", labels = c("HF","LF")) +
scale_color_manual(values = params$COL1, name = "Group", labels = c("HF-CTRL","HF-PFOS","LF-CTRL","LF-PFOS")) +
scale_shape_manual(name = "Day", label = c("d08" = "8","d21" = "21"), values = c("d08" = 19, "d12" = 1, "d16" = 17, "d21" = 2)) +
theme_pubr(border = TRUE) +
theme(axis.title.x = element_blank()) +
facet_wrap(.~comp_name, ncol = 4, nrow = 2, scales = "free_y") +
expand_limits(y = 0) +
guides(color = guide_legend(override.aes = list(size = 4, shape = 15, linetype = 0)),
shape = guide_legend(override.aes = list(size = 3)))
# Add statistics
p.stat <- p + stat_pvalue_manual(stat.in, label = "p.adj.signif", tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(stat.out, label = "p.adj.signif", tip.length = 0, hide.ns = TRUE) +
scale_y_continuous(expand = expansion(mult = c(0,0.1)), name = "mM compound")
p.stat# Save plot
suppressMessages(ggsave(filename = "plots/animal_data/scfa/scfa_concentrations_nested.pdf", plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 150, width = 200))
suppressMessages(ggsave(filename = "plots/animal_data/scfa/scfa_concentrations_nested.png", plot = p.stat, device = "png", dpi = 300, units = "mm", height = 150, width = 200))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())8.3 Principal component analysis (PCA)
8.3.1 DAtest (treatment)
load("R_objects/SCFA_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Test best method
filt.test <- testDA(t(dat.SCFA), predictor = dat.clean$treatment, effectSize = 10, relative = FALSE, k = c(1,1,2))## Warning in testDA(t(dat.SCFA), predictor = dat.clean$treatment, effectSize =
## 10, : Dataset contains very few features
## Running on 7 cores
## Warning in testDA(t(dat.SCFA), predictor = dat.clean$treatment, effectSize =
## 10, : Very few features spiked. Increase 'k' or set 'R' to more than 50 to
## ensure proper estimation of AUC and FPR
## predictor is assumed to be a categorical variable with 2 levels: CTRL, PFOS
## Spikeing...
## Testing 5 methods 20 times each...
##
|
| | 0%
|
|= | 1%
|
|= | 2%
|
|== | 3%
|
|=== | 4%
|
|==== | 5%
|
|==== | 6%
|
|===== | 7%
|
|====== | 8%
|
|====== | 9%
|
|======= | 10%
|
|======== | 11%
|
|======== | 12%
|
|========= | 13%
|
|========== | 14%
|
|========== | 15%
|
|=========== | 16%
|
|============ | 17%
|
|============= | 18%
|
|============= | 19%
|
|============== | 20%
|
|=============== | 21%
|
|=============== | 22%
|
|================ | 23%
|
|================= | 24%
|
|================== | 25%
|
|================== | 26%
|
|=================== | 27%
|
|==================== | 28%
|
|==================== | 29%
|
|===================== | 30%
|
|====================== | 31%
|
|====================== | 32%
|
|======================= | 33%
|
|======================== | 34%
|
|======================== | 35%
|
|========================= | 36%
|
|========================== | 37%
|
|=========================== | 38%
|
|=========================== | 39%
|
|============================ | 40%
|
|============================= | 41%
|
|============================= | 42%
|
|============================== | 43%
|
|=============================== | 44%
|
|================================ | 45%
|
|================================ | 46%
|
|================================= | 47%
|
|================================== | 48%
|
|================================== | 49%
|
|=================================== | 50%
|
|==================================== | 51%
|
|==================================== | 52%
|
|===================================== | 53%
|
|====================================== | 54%
|
|====================================== | 55%
|
|======================================= | 56%
|
|======================================== | 57%
|
|========================================= | 58%
|
|========================================= | 59%
|
|========================================== | 60%
|
|=========================================== | 61%
|
|=========================================== | 62%
|
|============================================ | 63%
|
|============================================= | 64%
|
|============================================== | 65%
|
|============================================== | 66%
|
|=============================================== | 67%
|
|================================================ | 68%
|
|================================================ | 69%
|
|================================================= | 70%
|
|================================================== | 71%
|
|================================================== | 72%
|
|=================================================== | 73%
|
|==================================================== | 74%
|
|==================================================== | 75%
|
|===================================================== | 76%
|
|====================================================== | 77%
|
|======================================================= | 78%
|
|======================================================= | 79%
|
|======================================================== | 80%
|
|========================================================= | 81%
|
|========================================================= | 82%
|
|========================================================== | 83%
|
|=========================================================== | 84%
|
|============================================================ | 85%
|
|============================================================ | 86%
|
|============================================================= | 87%
|
|============================================================== | 88%
|
|============================================================== | 89%
|
|=============================================================== | 90%
|
|================================================================ | 91%
|
|================================================================ | 92%
|
|================================================================= | 93%
|
|================================================================== | 94%
|
|================================================================== | 95%
|
|=================================================================== | 96%
|
|==================================================================== | 97%
|
|===================================================================== | 98%
|
|===================================================================== | 99%
|
|======================================================================| 100%
## Method AUC FPR FDR Power Score Score.5% Score.95%
## Log t-test (ltt) 1.00 0.0 0.00 1.00 0.50 0.19 0.50 *
## t-test (ttt) 1.00 0.0 0.00 1.00 0.50 0.19 0.50 *
## Wilcox (wil) 0.97 0.0 0.00 0.75 0.35 -0.02 0.50 *
## Permutation (per) 1.00 0.0 0.29 1.00 0.21 -0.38 0.50 *
## t-test - Rank (ttr) 0.56 0.5 0.45 0.50 -0.42 -0.56 -0.16
## Warning: The `fun.y` argument of `stat_summary()` is deprecated as of ggplot2 3.3.0.
## ℹ Please use the `fun` argument instead.
## ℹ The deprecated feature was likely used in the DAtest package.
## Please report the issue at <https://github.com/Russel88/DAtest/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The `fun.ymin` argument of `stat_summary()` is deprecated as of ggplot2 3.3.0.
## ℹ Please use the `fun.min` argument instead.
## ℹ The deprecated feature was likely used in the DAtest package.
## Please report the issue at <https://github.com/Russel88/DAtest/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The `fun.ymax` argument of `stat_summary()` is deprecated as of ggplot2 3.3.0.
## ℹ Please use the `fun.max` argument instead.
## ℹ The deprecated feature was likely used in the DAtest package.
## Please report the issue at <https://github.com/Russel88/DAtest/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## pval pval.adj log2FC ordering Feature
## acetic 8.758125e-05 1.751625e-04 0.2041175 LF>HF acetic
## formic 1.932949e-03 2.577265e-03 2.8436207 LF>HF formic
## propanoic 2.059501e-02 2.353715e-02 0.3332647 LF>HF propanoic
## m2_propanoic 4.067214e-09 3.253772e-08 2.0440321 LF>HF m2_propanoic
## butanoic 5.800573e-07 1.546819e-06 -1.1549635 HF>LF butanoic
## m3_butanoic 8.629517e-04 1.380723e-03 1.1528124 LF>HF m3_butanoic
## pentanoic 2.867293e-07 1.146917e-06 1.0109630 LF>HF pentanoic
## hexanoic 2.923496e-02 2.923496e-02 -1.0180949 HF>LF hexanoic
## Method
## acetic t-test (ttt)
## formic t-test (ttt)
## propanoic t-test (ttt)
## m2_propanoic t-test (ttt)
## butanoic t-test (ttt)
## m3_butanoic t-test (ttt)
## pentanoic t-test (ttt)
## hexanoic t-test (ttt)
## pval pval.adj log2FC ordering Feature
## acetic 0.9961145 0.9961145 0.0002715497 PFOS>CTRL acetic
## formic 0.2636677 0.7677208 0.8157610082 PFOS>CTRL formic
## propanoic 0.1809856 0.7677208 -0.1976392059 CTRL>PFOS propanoic
## m2_propanoic 0.5496795 0.7677208 0.2072936476 PFOS>CTRL m2_propanoic
## butanoic 0.6717557 0.7677208 0.1006386092 PFOS>CTRL butanoic
## m3_butanoic 0.2912375 0.7677208 -0.3550074801 CTRL>PFOS m3_butanoic
## pentanoic 0.4290549 0.7677208 0.1663651415 PFOS>CTRL pentanoic
## hexanoic 0.6446947 0.7677208 -0.2101378894 CTRL>PFOS hexanoic
## Method
## acetic t-test (ttt)
## formic t-test (ttt)
## propanoic t-test (ttt)
## m2_propanoic t-test (ttt)
## butanoic t-test (ttt)
## m3_butanoic t-test (ttt)
## pentanoic t-test (ttt)
## hexanoic t-test (ttt)
## Feature pval log2FC coverage ordering pval.adj
## 1 acetic 0.00010000 0.076500398 10000 LF>HF 0.000200000
## 2 formic 0.00059994 0.024004178 10000 LF>HF 0.000799920
## 3 propanoic 0.01779822 0.046041178 10000 LF>HF 0.017798220
## 4 m2_propanoic 0.00010000 0.013428597 10000 LF>HF 0.000200000
## 5 butanoic 0.00010000 -0.190083591 10000 HF>LF 0.000200000
## 6 m3_butanoic 0.00059994 0.004952697 10000 LF>HF 0.000799920
## 7 pentanoic 0.00010000 0.012306019 10000 LF>HF 0.000200000
## 8 hexanoic 0.00499950 -0.001605899 10000 HF>LF 0.005713714
## Method
## 1 Permutation (per)
## 2 Permutation (per)
## 3 Permutation (per)
## 4 Permutation (per)
## 5 Permutation (per)
## 6 Permutation (per)
## 7 Permutation (per)
## 8 Permutation (per)
## Feature pval log2FC coverage ordering pval.adj
## 1 acetic 0.09969003 0.000101823 1000 PFOS>CTRL 0.1993801
## 2 formic 0.27557244 0.008562522 10000 PFOS>CTRL 0.3443084
## 3 propanoic 0.17548245 -0.027357826 10000 CTRL>PFOS 0.2807719
## 4 m2_propanoic 0.05519448 0.001556962 1000 PFOS>CTRL 0.1898477
## 5 butanoic 0.07119288 0.017511891 1000 PFOS>CTRL 0.1898477
## 6 m3_butanoic 0.30126987 -0.001588705 10000 CTRL>PFOS 0.3443084
## 7 pentanoic 0.41855814 0.002087528 10000 PFOS>CTRL 0.4185581
## 8 hexanoic 0.06899310 -0.000347513 1000 CTRL>PFOS 0.1898477
## Method
## 1 Permutation (per)
## 2 Permutation (per)
## 3 Permutation (per)
## 4 Permutation (per)
## 5 Permutation (per)
## 6 Permutation (per)
## 7 Permutation (per)
## 8 Permutation (per)
Best tests for data: t-tests and PERMANOVA Significant impact from feed was detected for all compounds, but no difference for treatment in any testing method.
8.3.2 PERMANOVA and PCA (visualization)
# Load data
load("R_objects/SCFA_data.Rdata")
# Calculating scaled Principal Component Analysis
pca.scfa <- prcomp(as.matrix(dat.SCFA), scale. = TRUE)
pca.scfa$rotation <- -1*pca.scfa$rotation
pca.scfa$x <- -1*pca.scfa$x
pca.scfa$rotation## PC1 PC2 PC3 PC4 PC5
## acetic -0.4569132 0.3220678 -0.29649356 0.16085706 0.09802827
## formic 0.2920027 0.1107856 -0.25218344 0.69629231 0.53699070
## propanoic -0.3037349 0.1521728 -0.70293429 -0.27058879 0.04636900
## m2_propanoic 0.4539164 0.4107624 0.06023084 0.03348650 -0.22514426
## butanoic -0.4376758 0.3179732 0.33195864 0.09486100 -0.10140800
## m3_butanoic 0.2375204 0.3287457 0.10109655 -0.61885033 0.61798278
## pentanoic 0.2165469 0.6275817 -0.11503873 0.04556649 -0.41784432
## hexanoic -0.3358589 0.2984580 0.46593964 0.14460893 0.28707358
## PC6 PC7 PC8
## acetic 0.24697571 0.652250172 0.27871565
## formic 0.10087584 -0.208660135 -0.10939617
## propanoic -0.35153145 -0.266106002 -0.34744323
## m2_propanoic -0.22793307 0.482538661 -0.53385209
## butanoic 0.48613748 -0.287535501 -0.50877100
## m3_butanoic 0.23835737 -0.005997736 0.05967541
## pentanoic 0.04072268 -0.377214468 0.47475840
## hexanoic -0.67712407 -0.048696062 0.12973278
## PC1 PC2 PC3 PC4 PC5 PC6
## R01 1.6216522 -0.79840794 -0.010067003 0.91696195 0.912782382 -0.08189063
## R02 0.9530617 -0.33960856 0.147663930 -0.60712114 -0.447316304 -0.23596848
## R03 -0.2945006 -3.50171191 0.272491401 -0.11793283 0.152158657 -0.72878282
## R05 0.4980408 -1.69850661 0.795591257 -2.77972432 3.119713136 0.79413160
## R06 1.3428441 0.73876008 -0.454105736 -0.15050800 -0.300043429 -0.25192081
## R07 1.0066251 0.92773004 -0.400906330 -0.58890155 -0.975721516 -0.25030890
## R08 1.5858044 0.92661669 0.080499011 -0.96428297 -0.469644604 -0.17080287
## R09 1.3691320 0.78115275 -0.006498108 -1.01462081 -0.374971149 -0.21316744
## R10 0.6630036 0.21690845 0.542221597 -0.59121635 -0.365841548 0.07830816
## R11 1.7022801 0.30198959 0.323435182 -1.14228227 -0.182286183 -0.31069436
## R12 2.7847962 1.12902016 0.126601501 0.74683107 0.877559185 0.23207837
## R13 0.8294125 -1.04209568 -0.218549325 2.05077831 0.261463553 0.11173428
## R14 1.2425609 0.09544407 -0.247839208 0.55581434 -0.183144181 -0.07069110
## R15 1.0458655 -1.73121428 0.692922088 0.18365571 -1.070590831 -0.76036064
## R16 1.1959990 -0.39357029 0.176990527 -0.93476725 -0.200384715 -0.41769332
## R17 0.6535681 -0.53536988 -0.077395277 0.33382300 -1.388625628 -0.60205758
## R18 1.7328554 -0.17953567 -0.091888055 1.86208351 -0.501191397 -0.38249117
## R19 2.2411043 0.52081910 -0.401894736 1.91231895 1.141046088 0.29863420
## R20 2.5803655 0.18533610 0.547827210 -0.62109222 0.575387171 -0.24800750
## R21 1.7450516 1.81647795 -1.520088882 2.09828441 1.121592642 0.31010316
## R22 1.2351578 -0.66042771 0.750721267 -0.57156868 -0.349501701 -0.51549389
## R23 2.1094778 1.72228520 -0.471519274 0.24126633 -0.206480915 -0.12358708
## R24 2.2134833 1.06998868 -0.049602824 -0.16174938 -0.012531511 -0.19565891
## R25 -0.2174328 -0.36159486 0.004896641 -0.61637773 -0.281985349 0.20943545
## R26 -0.4499634 0.38706081 -2.329295584 -1.29448009 -0.375117122 -1.29244188
## R27 -1.8315064 -0.82590163 -1.262797380 -0.31683562 0.057068017 -0.41382335
## R28 -0.9910201 0.02520939 1.085927932 0.02355713 -0.107896407 0.59643158
## R29 -1.9481932 0.85037507 -1.421817522 -0.42556951 -0.115815465 -0.18956538
## R30 -1.0484581 -1.15869382 -0.941806728 2.21881808 1.223997969 0.49815788
## R31 -1.4034418 0.19289525 -2.511813257 -0.26621217 0.259745099 -0.25496752
## R32 -1.3518931 0.70975263 0.020095737 -0.51927479 -0.004660989 1.22601443
## R33 -0.4306888 1.17566924 0.232614203 -0.54258270 -0.405538144 1.05202492
## R34 -4.6236994 3.15251220 0.227924751 0.28037357 1.232773210 -0.90878879
## R35 -1.5311236 -0.27928619 -1.345500652 -0.40475432 -0.167019907 0.18729551
## R36 -2.4466967 1.28635709 3.494307030 1.57107194 -0.060964879 -1.66529731
## R37 -1.6259406 -0.17805050 1.052468580 0.41025591 -0.544931592 1.31684568
## R38 -1.0205859 -0.82240644 1.011858138 0.05011188 -0.270305021 1.30762316
## R39 -2.2490465 -0.70931765 -0.097586672 0.69577116 -0.502357666 1.18516726
## R40 0.4792411 -3.85145548 1.750003086 0.25627926 0.122780360 -0.09215686
## R41 -2.3385858 1.52527541 1.794725476 -0.42492983 1.191504144 -1.33514545
## R42 -1.8688355 -0.35644798 -0.411538288 0.27681190 -0.978575166 0.67120018
## R43 0.3578997 1.46878703 0.536471335 -1.06708362 -0.168799310 1.04659492
## R44 -1.6242760 -0.95661682 -1.272809476 -0.15333188 -0.201863570 -0.04402847
## R45 0.5365755 1.98275866 1.026253211 -0.84950440 -0.302302148 0.91264811
## R46 -1.1957354 -1.92226391 -0.583180879 0.18499246 -0.195019004 -0.14560301
## R47 -1.5783080 0.61584438 0.574607073 0.83878140 -1.124285114 0.48689756
## R48 -1.6559268 -1.50254220 -1.140616965 -0.58193785 0.586140851 -0.61993092
## PC7 PC8
## R01 -0.0005809426 -0.129087269
## R02 0.0171989993 0.429005530
## R03 -0.1452228136 -0.479416641
## R05 0.4641861041 0.123038901
## R06 -0.0962599980 0.157811744
## R07 -0.0123408654 0.685307486
## R08 0.4768856494 0.355475933
## R09 0.4192727682 0.045518668
## R10 0.0026118322 0.127602282
## R11 0.2878649755 -0.017062428
## R12 -0.0128094026 -0.141179355
## R13 0.0993528243 0.354837683
## R14 -0.0293386139 0.562402328
## R15 -0.0583561648 -0.355207240
## R16 0.0028549686 -0.058320809
## R17 0.4313125319 0.191108927
## R18 0.5900724267 -0.242975159
## R19 -0.5881890910 -0.002172169
## R20 -0.1156138552 -0.363173500
## R21 -0.1565918020 -0.193466652
## R22 -0.0735653429 0.088697380
## R23 0.2284546940 0.090367513
## R24 -0.1088241664 -0.137771669
## R25 -0.4893907827 -0.258845613
## R26 -0.4113465018 -1.047455781
## R27 -0.0626530466 0.067140086
## R28 0.0135094505 -0.098751014
## R29 0.1661000579 0.049587367
## R30 0.0882575160 -0.072963193
## R31 -0.7112010281 0.337749505
## R32 0.3038533561 -0.833327789
## R33 0.1328344048 -0.342867992
## R34 1.1475584020 0.014208472
## R35 -0.0833786625 0.547401760
## R36 0.0158815286 -0.268977514
## R37 -0.5459921691 0.125304154
## R38 -0.4662016177 0.077296066
## R39 0.6516563652 0.195679135
## R40 0.1429796023 0.100613724
## R41 -1.3506099762 0.534010957
## R42 -0.8905609549 -0.244932035
## R43 -0.2125186879 -0.164162584
## R44 0.1217644205 0.269895782
## R45 -0.0745691957 0.047106009
## R46 0.4449809220 0.322929002
## R47 0.2493925646 -0.240755794
## R48 0.1972793165 -0.207224192
# Calculate explained variance in each principal component
varex <- data.frame("PC" = 1:8, "variance" = pca.scfa$sdev^2 / sum(pca.scfa$sdev^2))
var.plot <- ggplot(varex, aes(x = PC, y = variance)) +
geom_line() +
geom_point() +
xlab("PC") + ylab("Variance explained") + ylim(0,1)
var.plot# Prepare data for plotting
mds.samples <- data.frame(pca.scfa$x)
mds.scfa <- data.frame(pca.scfa$rotation)
mds.scfa$label1 <- row.names(pca.scfa$rotation)
# Renaming compounds to common name
mds.scfa$label2 <- case_when(mds.scfa$label1 == "formic" ~ "Formate", mds.scfa$label1 == "acetic" ~ "Acetate", mds.scfa$label1 == "propanoic" ~ "Propionate", mds.scfa$label1 == "m2_propanoic" ~ "Isobutyrate", mds.scfa$label1 == "butanoic" ~ "Butyrate", mds.scfa$label1 == "m3_butanoic" ~ "Isovalerate",mds.scfa$label1 == "pentanoic" ~ "Valerate", mds.scfa$label1 == "m4_pentanoic" ~ "Isocaproate", mds.scfa$label1 == "hexanoic" ~ "Caproate", mds.scfa$label1 == "heptanoic" ~ "Enanthate")
# Setting stating point for arrows
mds.scfa$x <- 0
mds.scfa$y <- 0
# Bind PCA data with main data
dat.mds <- cbind(dat.clean, mds.samples)
# PERMANOVA
perm <- adonis2(dat.SCFA ~ feed*treatment*dissection, data = dat.mds, permutations = 999, na.action = na.omit)
perm## Permutation test for adonis under reduced model
## Terms added sequentially (first to last)
## Permutation: free
## Number of permutations: 999
##
## adonis2(formula = dat.SCFA ~ feed * treatment * dissection, data = dat.mds, permutations = 999, na.action = na.omit)
## Df SumOfSqs R2 F Pr(>F)
## feed 1 0.83364 0.43837 36.1803 0.001 ***
## treatment 1 0.03172 0.01668 1.3765 0.246
## dissection 1 0.04702 0.02472 2.0405 0.129
## feed:treatment 1 0.02490 0.01309 1.0805 0.311
## feed:dissection 1 0.00550 0.00289 0.2388 0.837
## treatment:dissection 1 0.03474 0.01827 1.5079 0.215
## feed:treatment:dissection 1 0.02557 0.01345 1.1098 0.293
## Residual 39 0.89861 0.47253
## Total 46 1.90170 1.00000
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
8.3.3 Create figure
# Create plot
p <- ggplot() +
geom_point(data = dat.mds, mapping = aes(x = PC1, y = PC2, color = feedtreat, shape = dissection, group = feedtreat), size = 2) +
stat_ellipse(data = dat.mds, mapping = aes(x = PC1, y = PC2, color = feedtreat, fill = feedtreat), geom = "polygon", alpha = 0.1) +
geom_segment(data = mds.scfa, mapping = aes(x=x, y=y, xend=3*PC1, yend=3*PC2),
lineend = "butt",
linejoin = "round",
size = 0.5,
arrow = arrow(length = unit(0.2, 'cm'))) +
geom_label_repel(data = mds.scfa,
mapping = aes(x = 3*PC1, y =3*PC2),
label = mds.scfa$label2,
size = 4,
min.segment.length = 0,
segment.alpha = 0.8,
box.padding = 0.5,
force = 1) +
theme_pubr(legend = "right") +
scale_color_manual(values = params$COL1, name = "Feed & treatment", labels = c("HF_CTRL" = "HF", "HF_PFOS" = "HF + PFOS","LF_CTRL" = "LF","LF_PFOS" = "LF + PFOS")) +
scale_shape_manual(values = c("d08" = 19, "d12" = 1, "d16" = 17, "d21" = 2), name = "Day", labels = c("d08" = "8","d21" = "21")) +
scale_fill_manual(values = params$COL1) +
labs(x = "PC1", y = "PC2") +
guides(fill = "none")
p
# Remove legend
leg <- get_legend(p)
p2 <- p + theme(legend.position = "none")
# Add marginal boxplots
p3 <- ggExtra::ggMarginal(p = p2, type = "boxplot", size = 10, groupFill = TRUE)
p3# Add legend back to plot
p4 <- plot_grid(p3, leg, ncol = 2, rel_heights = 1, rel_widths = c(0.8,0.2))
p4## Permutation test for adonis under reduced model
## Terms added sequentially (first to last)
## Permutation: free
## Number of permutations: 999
##
## adonis2(formula = dat.SCFA ~ feed * treatment * dissection, data = dat.mds, permutations = 999, na.action = na.omit)
## Df SumOfSqs R2 F Pr(>F)
## feed 1 0.83364 0.43837 36.1803 0.001 ***
## treatment 1 0.03172 0.01668 1.3765 0.246
## dissection 1 0.04702 0.02472 2.0405 0.129
## feed:treatment 1 0.02490 0.01309 1.0805 0.311
## feed:dissection 1 0.00550 0.00289 0.2388 0.837
## treatment:dissection 1 0.03474 0.01827 1.5079 0.215
## feed:treatment:dissection 1 0.02557 0.01345 1.1098 0.293
## Residual 39 0.89861 0.47253
## Total 46 1.90170 1.00000
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Save output
suppressMessages(ggsave(filename = "plots/animal_data/scfa/PCOA_weighed.png", plot = p3, device = "png", dpi = 300, height = 130, width = 130, units = "mm"))
suppressMessages(ggsave(filename = "plots/animal_data/scfa/PCOA_weighed.pdf", plot = p3, device = "pdf", dpi = 300, height = 130, width = 130, units = "mm"))
# clear the environment and release memory
rm(list = ls(all.names = TRUE))
invisible(gc())9 PH DATA
Here we examine pH data recorded from 1:5 dilutions of gastrointestinal content from upper and lower jejunum, ileum, and cecum.
9.1 Prepare data
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
# Isolate pH data and pivor longer
dat.clean <- dat %>% select(rat_name, treatment, feed, feedtreat, feedtreatday, dissection, pH_je_up, pH_je_down, pH_ileum, pH_cecum) %>% pivot_longer(., cols = c(pH_je_up, pH_je_down, pH_ileum, pH_cecum), names_to = "group", values_to = "pH")
# Remove rows with NA
dat.clean <- subset(dat.clean, !is.na(pH))
for (i in dat.clean$rat_name) {
dat.clean$grfeed <- paste0(dat.clean$group,"_",dat.clean$feed)
dat.clean$grday <- paste0(dat.clean$group,"_",dat.clean$dissection)
dat.clean$feedday <-paste0(dat.clean$feed,"_",dat.clean$dissection)
}
df_order <- c("pH_je_up","pH_je_down","pH_ileum","pH_cecum")
dat.clean$group <- factor(as.character(dat.clean$group), levels = df_order)
# Set names of variables
PREDICTOR <- "grfeed"
OUTCOME <- "pH"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(c("feed","grfeed","treatment")))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 16 × 7
## treatment feed grfeed variable n mean sd
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl>
## 1 CTRL HF pH_cecum_HF pH 12 6.41 0.404
## 2 PFOS HF pH_cecum_HF pH 12 6.73 0.781
## 3 CTRL HF pH_ileum_HF pH 12 7.97 0.411
## 4 PFOS HF pH_ileum_HF pH 12 7.83 0.357
## 5 CTRL HF pH_je_down_HF pH 12 7.17 0.398
## 6 PFOS HF pH_je_down_HF pH 12 7.32 0.477
## 7 CTRL HF pH_je_up_HF pH 12 6.98 0.239
## 8 PFOS HF pH_je_up_HF pH 12 7.06 0.314
## 9 CTRL LF pH_cecum_LF pH 11 8.65 0.186
## 10 PFOS LF pH_cecum_LF pH 12 8.48 0.306
## 11 CTRL LF pH_ileum_LF pH 12 8.16 0.359
## 12 PFOS LF pH_ileum_LF pH 12 7.84 0.453
## 13 CTRL LF pH_je_down_LF pH 12 7.05 0.46
## 14 PFOS LF pH_je_down_LF pH 12 7.24 0.276
## 15 CTRL LF pH_je_up_LF pH 12 6.87 0.368
## 16 PFOS LF pH_je_up_LF pH 12 6.96 0.384
dat.clean %>% group_by(across(all_of(c("feed","grfeed","treatment")))) %>% get_summary_stats(!!sym(OUTCOME), type = "full")## # A tibble: 16 × 16
## treatment feed grfeed variable n min max median q1 q3 iqr
## <chr> <chr> <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 CTRL HF pH_cecum… pH 12 6.02 7.42 6.26 6.12 6.62 0.5
## 2 PFOS HF pH_cecum… pH 12 5.55 8.52 6.64 6.28 7.02 0.732
## 3 CTRL HF pH_ileum… pH 12 7.32 8.57 7.98 7.76 8.32 0.56
## 4 PFOS HF pH_ileum… pH 12 7.27 8.32 7.89 7.56 8.02 0.463
## 5 CTRL HF pH_je_do… pH 12 6.65 8.04 7.26 6.88 7.35 0.465
## 6 PFOS HF pH_je_do… pH 12 6.48 7.96 7.36 6.98 7.68 0.697
## 7 CTRL HF pH_je_up… pH 12 6.73 7.45 6.88 6.83 7.08 0.247
## 8 PFOS HF pH_je_up… pH 12 6.63 7.68 7.04 6.82 7.22 0.392
## 9 CTRL LF pH_cecum… pH 11 8.24 8.94 8.68 8.57 8.76 0.19
## 10 PFOS LF pH_cecum… pH 12 7.87 9.09 8.51 8.32 8.60 0.282
## 11 CTRL LF pH_ileum… pH 12 7.56 8.86 8.20 7.94 8.35 0.407
## 12 PFOS LF pH_ileum… pH 12 6.79 8.58 7.92 7.68 8.07 0.385
## 13 CTRL LF pH_je_do… pH 12 5.95 7.66 7.02 6.89 7.33 0.445
## 14 PFOS LF pH_je_do… pH 12 6.67 7.57 7.28 7.10 7.45 0.345
## 15 CTRL LF pH_je_up… pH 12 6.18 7.47 6.84 6.75 7.16 0.413
## 16 PFOS LF pH_je_up… pH 12 6.32 7.61 6.95 6.76 7.25 0.493
## # ℹ 5 more variables: mad <dbl>, mean <dbl>, sd <dbl>, se <dbl>, ci <dbl>
# Create plot
bxp <- dat.clean %>%
ggboxplot(x = "group",#if_else(length(PREDICTOR) > 1, PREDICTOR[2],PREDICTOR[1]),
y = OUTCOME,
color = "feedtreat",#PREDICTOR[1],
facet.by = "dissection",#if(length(PREDICTOR) == 3) PREDICTOR[3],
palette = params$COL)
bxp# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 4 × 13
## grfeed rat_name treatment feed feedtreat feedtreatday dissection group pH
## <chr> <chr> <chr> <chr> <chr> <chr> <chr> <fct> <dbl>
## 1 pH_cec… R40 PFOS HF HF_PFOS HF_PFOS_d08 d08 pH_c… 8.52
## 2 pH_cec… R17 PFOS LF LF_PFOS LF_PFOS_d08 d08 pH_c… 7.87
## 3 pH_ile… R14 PFOS LF LF_PFOS LF_PFOS_d08 d08 pH_i… 6.79
## 4 pH_je_… R12 CTRL LF LF_CTRL LF_CTRL_d21 d21 pH_j… 5.95
## # ℹ 4 more variables: grday <chr>, feedday <chr>, is.outlier <lgl>,
## # is.extreme <lgl>
# Check normality
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.974 0.00116
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 7 183 2.16 0.0401
## Warning in leveneTest.default(y = y, group = group, ...): group coerced to
## factor.
# Save dat.clean
save(dat.clean, model, EQUAL.VAR, FORMULA,OUTCOME,PREDICTOR,PREDICTOR.F,SUBJECT, file = "plots/animal_data/pH/ph_data.Rdata")This shows that data has four outliers, is not normally distribution and does not have equal variance. Therefore we can test the data with a Kruskal-Wallis with posthoc Dunn’s test adjusted p-values.
9.2 Kruskal-Wallis test
Perform test
## # A tibble: 1 × 6
## .y. n statistic df p method
## * <chr> <int> <dbl> <int> <dbl> <chr>
## 1 pH 191 130. 7 7.25e-25 Kruskal-Wallis
Effect size
The eta squared, based on the H-statistic, can be used as the measure of the Kruskal-Wallis test effect size. The interpretation values commonly in published literature are: 0.01- < 0.06 (small effect), 0.06 - < 0.14 (moderate effect) and >= 0.14 (large effect).
## # A tibble: 1 × 5
## .y. n effsize method magnitude
## * <chr> <int> <dbl> <chr> <ord>
## 1 pH 191 0.671 eta2[H] large
Post-hoc test if interaction is significant
A significant Kruskal-Wallis test is generally followed up by Dunn’s test to identify which groups are different. It’s also possible to use the Wilcoxon’s test to calculate pairwise comparisons between group levels with corrections for multiple testing.
## # A tibble: 28 × 9
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## * <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 pH pH_cecum_HF pH_ce… 24 23 8.72 2.79e-18 7.82e-17 ****
## 2 pH pH_cecum_HF pH_il… 24 24 6.39 1.64e-10 9.18e-10 ****
## 3 pH pH_cecum_HF pH_il… 24 24 6.80 1.08e-11 7.57e-11 ****
## 4 pH pH_cecum_HF pH_je… 24 24 3.19 1.44e- 3 2.52e- 3 **
## 5 pH pH_cecum_HF pH_je… 24 24 2.83 4.67e- 3 7.69e- 3 **
## 6 pH pH_cecum_HF pH_je… 24 24 1.86 6.30e- 2 8.82e- 2 ns
## 7 pH pH_cecum_HF pH_je… 24 24 1.43 1.52e- 1 1.94e- 1 ns
## 8 pH pH_cecum_LF pH_il… 23 24 -2.40 1.66e- 2 2.58e- 2 *
## 9 pH pH_cecum_LF pH_il… 23 24 -2.00 4.58e- 2 6.75e- 2 ns
## 10 pH pH_cecum_LF pH_je… 23 24 -5.57 2.59e- 8 1.04e- 7 ****
## # ℹ 18 more rows
Several groups show significant difference based of compartment, feed and day of sampling. We will plot this as a nested analysis with feed and day as a combined inner variable and compartment (group) as the outer variable, using kruskal-wallis with posthoc Dunn’s test for both.
9.3 Create figure (day)
# ## Comparison for inner variable
stat.in <- dat.clean %>%
group_by(dissection,group) %>%
wilcox_test(pH ~ feedday) %>%
adjust_pvalue(method = "BH") %>%
add_significance("p.adj") %>%
add_xy_position(x = "group", dodge = 0.8) %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 8 × 17
## dissection group .y. group1 group2 n1 n2 statistic p p.adj
## * <chr> <fct> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl>
## 1 d08 pH_je_up pH HF_d08 LF_d08 12 12 65 7.07e-1 8.08e-1
## 2 d08 pH_je_do… pH HF_d08 LF_d08 12 12 71 9.77e-1 9.77e-1
## 3 d08 pH_ileum pH HF_d08 LF_d08 12 12 59 4.78e-1 6.51e-1
## 4 d08 pH_cecum pH HF_d08 LF_d08 12 11 6 2.49e-4 9.96e-4
## 5 d21 pH_je_up pH HF_d21 LF_d21 12 12 109 3.5 e-2 9.33e-2
## 6 d21 pH_je_do… pH HF_d21 LF_d21 12 12 84.5 4.88e-1 6.51e-1
## 7 d21 pH_ileum pH HF_d21 LF_d21 12 12 59 4.7 e-1 6.51e-1
## 8 d21 pH_cecum pH HF_d21 LF_d21 12 12 0 7.4 e-7 5.92e-6
## # ℹ 7 more variables: p.adj.signif <chr>, y.position <dbl>,
## # groups <named list>, x <dbl>, xmin <dbl>, xmax <dbl>, p.adj.format <chr>
## Comparison for outer variable
stat.out <- dat.clean %>%
group_by(dissection) %>%
kruskal_test(pH ~ group) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 2 × 9
## dissection .y. n statistic df p method p.signif p.format
## * <chr> <chr> <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 d08 pH 95 20.7 3 0.000121 Kruskal-… *** <0.001
## 2 d21 pH 96 33.5 3 0.000000249 Kruskal-… **** <0.001
pwc1 <- dat.clean %>%
group_by(dissection) %>%
dunn_test(pH ~ group) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE) %>%
add_xy_position(x = "group", dodge = 0.8)
pwc1## # A tibble: 12 × 15
## dissection .y. group1 group2 n1 n2 statistic p p.adj
## <chr> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl>
## 1 d08 pH pH_je_up pH_je_down 24 24 0.406 6.85e-1 6.85e-1
## 2 d08 pH pH_je_up pH_ileum 24 24 4.06 4.84e-5 2.91e-4
## 3 d08 pH pH_je_up pH_cecum 24 23 2.15 3.17e-2 1.27e-1
## 4 d08 pH pH_je_down pH_ileum 24 24 3.66 2.55e-4 1.27e-3
## 5 d08 pH pH_je_down pH_cecum 24 23 1.75 8.08e-2 1.84e-1
## 6 d08 pH pH_ileum pH_cecum 24 23 -1.87 6.12e-2 1.84e-1
## 7 d21 pH pH_je_up pH_je_down 24 24 2.37 1.79e-2 3.58e-2
## 8 d21 pH pH_je_up pH_ileum 24 24 5.73 9.84e-9 5.90e-8
## 9 d21 pH pH_je_up pH_cecum 24 24 3.16 1.56e-3 6.24e-3
## 10 d21 pH pH_je_down pH_ileum 24 24 3.37 7.64e-4 3.82e-3
## 11 d21 pH pH_je_down pH_cecum 24 24 0.795 4.26e-1 4.26e-1
## 12 d21 pH pH_ileum pH_cecum 24 24 -2.57 1.02e-2 3.05e-2
## # ℹ 6 more variables: p.adj.signif <chr>, p.adj.format <chr>, y.position <dbl>,
## # groups <named list>, xmin <dbl>, xmax <dbl>
# Test between days
stat.out2 <- dat.clean %>%
# group_by(feed) %>%
kruskal_test(pH ~ grday) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 2 × 9
## dissection .y. n statistic df p method p.signif p.format
## * <chr> <chr> <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 d08 pH 95 20.7 3 0.000121 Kruskal-… *** <0.001
## 2 d21 pH 96 33.5 3 0.000000249 Kruskal-… **** <0.001
pwc2 <- dat.clean %>%
# group_by(feed) %>%
dunn_test(pH ~ grday) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE) %>%
add_xy_position(x = "group", dodge = 0.8)
pwc2## # A tibble: 28 × 14
## .y. group1 group2 n1 n2 statistic p p.adj p.adj.signif
## <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl> <chr>
## 1 pH pH_cecum_d08 pH_cec… 23 24 -0.321 7.48e-1 1 ns
## 2 pH pH_cecum_d08 pH_ile… 23 24 1.88 5.95e-2 0.714 ns
## 3 pH pH_cecum_d08 pH_ile… 23 24 2.30 2.15e-2 0.318 ns
## 4 pH pH_cecum_d08 pH_je_… 23 24 -1.40 1.63e-1 1 ns
## 5 pH pH_cecum_d08 pH_je_… 23 24 -1.51 1.30e-1 1 ns
## 6 pH pH_cecum_d08 pH_je_… 23 24 -1.66 9.62e-2 1 ns
## 7 pH pH_cecum_d08 pH_je_… 23 24 -3.94 8.05e-5 0.00201 **
## 8 pH pH_cecum_d21 pH_ile… 24 24 2.23 2.58e-2 0.335 ns
## 9 pH pH_cecum_d21 pH_ile… 24 24 2.65 8.08e-3 0.145 ns
## 10 pH pH_cecum_d21 pH_je_… 24 24 -1.09 2.77e-1 1 ns
## # ℹ 18 more rows
## # ℹ 5 more variables: p.adj.format <chr>, y.position <dbl>,
## # groups <named list>, xmin <dbl>, xmax <dbl>
# Adjust x positions of inner statistics
stat.in$xmin <- c(0.8,1.8,2.8,3.8,0.8,1.8,2.8,3.8)
stat.in$xmax <- c(1.2,2.2,3.2,4.2,1.2,2.2,3.2,4.2)
# Create plot
p <- ggplot(dat.clean, aes(x = group, y = pH)) +
geom_boxplot(aes(fill = feed, color = feed), outlier.shape = NA) +
geom_point(aes(color = feed), position = position_jitterdodge(jitter.width = 0.15, dodge.width = 0.8), size = 0.8) +
scale_color_manual(values = c("black","black","black","black")) +
scale_fill_manual(values = params$COLFEED, name = "Feed") +
facet_wrap(.~dissection, ncol = 2, nrow = 1, labeller = labeller("dissection" = c("d08" = "Day 8","d21" = "Day 21"))) +
scale_y_continuous(name = "pH", breaks = seq(6,12,1), limits = c(5.5,10)) +
scale_x_discrete(name = "Compartment", labels = c("pH_je_up" = "Jejunum\nUpper","pH_je_down" = "Jejunum\nLower","pH_ileum" = "Ileum","pH_cecum" = "Cecum")) +
theme_pubr(legend = "top") +
guides(color = "none", linetype = "none") +
theme(axis.title.x = element_blank())
p# Add statistics to plot
p.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc1, tip.length = 0, hide.ns = TRUE, y.position = c(9,9.3,9,9.3,9.6,8.7,9.9))
p.stat# Save plot
suppressMessages(ggsave(filename = "plots/animal_data/pH/pH_all_groups_v2.pdf", plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 200))
suppressMessages(ggsave(filename = "plots/animal_data/pH/pH_all_groups_v2.png", plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 200))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())9.4 Create figure (PFOS)
# Load data
load("plots/animal_data/pH/ph_data.Rdata")
## Comparison for inner variable
stat.in <- dat.clean %>%
group_by(dissection,group) %>%
kruskal_test(pH ~ feedtreat) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 8 × 10
## dissection group .y. n statistic df p method p.signif p.format
## * <chr> <fct> <chr> <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 d08 pH_je… pH 24 1.57 3 6.67e-1 Krusk… ns 0.6670
## 2 d08 pH_je… pH 24 0.620 3 8.92e-1 Krusk… ns 0.8920
## 3 d08 pH_il… pH 24 0.980 3 8.06e-1 Krusk… ns 0.8060
## 4 d08 pH_ce… pH 23 14.6 3 2.21e-3 Krusk… ** 0.0022
## 5 d21 pH_je… pH 24 5.14 3 1.62e-1 Krusk… ns 0.1620
## 6 d21 pH_je… pH 24 3.31 3 3.46e-1 Krusk… ns 0.3460
## 7 d21 pH_il… pH 24 5.65 3 1.3 e-1 Krusk… ns 0.1300
## 8 d21 pH_ce… pH 24 17.9 3 4.51e-4 Krusk… *** <0.001
pwc1 <- dat.clean %>%
group_by(dissection,group) %>%
dunn_test(pH ~ feedtreat) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc1## # A tibble: 48 × 12
## dissection group .y. group1 group2 n1 n2 statistic p p.adj
## * <chr> <fct> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl>
## 1 d08 pH_je_up pH HF_CTRL HF_PFOS 6 6 0.817 0.414 1
## 2 d08 pH_je_up pH HF_CTRL LF_CTRL 6 6 0.265 0.791 1
## 3 d08 pH_je_up pH HF_CTRL LF_PFOS 6 6 1.12 0.261 1
## 4 d08 pH_je_up pH HF_PFOS LF_CTRL 6 6 -0.551 0.581 1
## 5 d08 pH_je_up pH HF_PFOS LF_PFOS 6 6 0.306 0.759 1
## 6 d08 pH_je_up pH LF_CTRL LF_PFOS 6 6 0.858 0.391 1
## 7 d08 pH_je_down pH HF_CTRL HF_PFOS 6 6 0.776 0.438 1
## 8 d08 pH_je_down pH HF_CTRL LF_CTRL 6 6 0.490 0.624 1
## 9 d08 pH_je_down pH HF_CTRL LF_PFOS 6 6 0.367 0.713 1
## 10 d08 pH_je_down pH HF_PFOS LF_CTRL 6 6 -0.286 0.775 1
## # ℹ 38 more rows
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Comparison for outer variable
stat.out <- dat.clean %>%
group_by(dissection) %>%
kruskal_test(pH ~ group) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 2 × 9
## dissection .y. n statistic df p method p.signif p.format
## * <chr> <chr> <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 d08 pH 95 20.7 3 0.000121 Kruskal-… *** <0.001
## 2 d21 pH 96 33.5 3 0.000000249 Kruskal-… **** <0.001
pwc2 <- dat.clean %>%
group_by(dissection) %>%
dunn_test(pH ~ group) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 12 × 11
## dissection .y. group1 group2 n1 n2 statistic p p.adj
## * <chr> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl>
## 1 d08 pH pH_je_up pH_je_down 24 24 0.406 6.85e-1 6.85e-1
## 2 d08 pH pH_je_up pH_ileum 24 24 4.06 4.84e-5 2.91e-4
## 3 d08 pH pH_je_up pH_cecum 24 23 2.15 3.17e-2 1.27e-1
## 4 d08 pH pH_je_down pH_ileum 24 24 3.66 2.55e-4 1.27e-3
## 5 d08 pH pH_je_down pH_cecum 24 23 1.75 8.08e-2 1.84e-1
## 6 d08 pH pH_ileum pH_cecum 24 23 -1.87 6.12e-2 1.84e-1
## 7 d21 pH pH_je_up pH_je_down 24 24 2.37 1.79e-2 3.58e-2
## 8 d21 pH pH_je_up pH_ileum 24 24 5.73 9.84e-9 5.90e-8
## 9 d21 pH pH_je_up pH_cecum 24 24 3.16 1.56e-3 6.24e-3
## 10 d21 pH pH_je_down pH_ileum 24 24 3.37 7.64e-4 3.82e-3
## 11 d21 pH pH_je_down pH_cecum 24 24 0.795 4.26e-1 4.26e-1
## 12 d21 pH pH_ileum pH_cecum 24 24 -2.57 1.02e-2 3.05e-2
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Calculate positions statistics on plot
pwc1 <- pwc1 %>% add_xy_position(x = "group", dodge = 0.8)
pwc2 <- pwc2 %>% add_xy_position(x = "group")
# Create plot
p <- ggboxplot(dat.clean, x = "group", y = "pH",
fill = "feedtreat",
color = "feedtreat",
add = "jitter",
add.params = list(size = 0.8)) +
theme_pubr(legend = "top") +
scale_color_manual(values = c("black","black","black","black")) +
scale_fill_manual(values = c("HF_d08" = "#d2e9cc","HF_d21" = "#32a248","LF_d08" = "#bde7fb","LF_d21" = "#1879b7"), name = "Feed per day", labels = c("HF Day 8","HF Day 21","LF Day 8","LF Day 21")) +
scale_alpha_manual(values = c(1,0.5,1,0.5)) +
scale_y_continuous(name = "pH", breaks = seq(6,12,1)) +
scale_x_discrete(name = "Compartment", labels = c("pH_je_up" = "Jejunum\nUpper","pH_je_down" = "Jejunum\nLower","pH_ileum" = "Ileum","pH_cecum" = "Cecum")) +
theme(axis.title.x = element_blank()) +
guides(color = "none") +
facet_wrap("dissection ~.", ncol = 2, nrow = 1)
p.stat <- p + stat_pvalue_manual(pwc1, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, tip.length = 0, hide.ns = TRUE)
p.statsuppressMessages(ggsave(filename = "plots/animal_data/pH/pH_all_pfos.pdf", plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 200))
suppressMessages(ggsave(filename = "plots/animal_data/pH/pH_all_pfos.png", plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 200))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())9.5 Create figure (feed)
# Load data
load("plots/animal_data/pH/ph_data.Rdata")
## Comparison for inner variable
stat.in <- dat.clean %>%
group_by(feed,group) %>%
kruskal_test(pH ~ feedtreat) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 8 × 10
## feed group .y. n statistic df p method p.signif p.format
## * <chr> <fct> <chr> <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 HF pH_je_up pH 24 0.214 1 0.644 Kruskal… ns 0.644
## 2 HF pH_je_down pH 24 0.853 1 0.356 Kruskal… ns 0.356
## 3 HF pH_ileum pH 24 0.802 1 0.371 Kruskal… ns 0.371
## 4 HF pH_cecum pH 24 1.20 1 0.273 Kruskal… ns 0.273
## 5 LF pH_je_up pH 24 0.654 1 0.419 Kruskal… ns 0.419
## 6 LF pH_je_down pH 24 0.964 1 0.326 Kruskal… ns 0.326
## 7 LF pH_ileum pH 24 3.00 1 0.0832 Kruskal… ns 0.083
## 8 LF pH_cecum pH 23 3.30 1 0.0691 Kruskal… ns 0.069
pwc1 <- dat.clean %>%
group_by(feed,group) %>%
dunn_test(pH ~ feedtreat) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc1## # A tibble: 8 × 12
## feed group .y. group1 group2 n1 n2 statistic p p.adj
## * <chr> <fct> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl>
## 1 HF pH_je_up pH HF_CTRL HF_PFOS 12 12 0.462 0.644 0.644
## 2 HF pH_je_down pH HF_CTRL HF_PFOS 12 12 0.924 0.356 0.356
## 3 HF pH_ileum pH HF_CTRL HF_PFOS 12 12 -0.895 0.371 0.371
## 4 HF pH_cecum pH HF_CTRL HF_PFOS 12 12 1.10 0.273 0.273
## 5 LF pH_je_up pH LF_CTRL LF_PFOS 12 12 0.808 0.419 0.419
## 6 LF pH_je_down pH LF_CTRL LF_PFOS 12 12 0.982 0.326 0.326
## 7 LF pH_ileum pH LF_CTRL LF_PFOS 12 12 -1.73 0.0832 0.0832
## 8 LF pH_cecum pH LF_CTRL LF_PFOS 11 12 -1.82 0.0691 0.0691
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Comparison for outer variable
stat.out <- dat.clean %>%
group_by(feed) %>%
kruskal_test(pH ~ group) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## # A tibble: 2 × 9
## feed .y. n statistic df p method p.signif p.format
## * <chr> <chr> <int> <dbl> <int> <dbl> <chr> <chr> <chr>
## 1 HF pH 96 52.4 3 2.49e-11 Kruskal-Wallis **** <0.001
## 2 LF pH 95 71.6 3 1.97e-15 Kruskal-Wallis **** <0.001
pwc2 <- dat.clean %>%
group_by(feed) %>%
dunn_test(pH ~ group) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 12 × 11
## feed .y. group1 group2 n1 n2 statistic p p.adj
## * <chr> <chr> <chr> <chr> <int> <int> <dbl> <dbl> <dbl>
## 1 HF pH pH_je_up pH_je_down 24 24 1.43 1.53e- 1 1.53e- 1
## 2 HF pH pH_je_up pH_ileum 24 24 4.74 2.15e- 6 1.08e- 5
## 3 HF pH pH_je_up pH_cecum 24 24 -2.32 2.03e- 2 4.05e- 2
## 4 HF pH pH_je_down pH_ileum 24 24 3.31 9.29e- 4 2.79e- 3
## 5 HF pH pH_je_down pH_cecum 24 24 -3.75 1.78e- 4 7.10e- 4
## 6 HF pH pH_ileum pH_cecum 24 24 -7.06 1.66e-12 9.98e-12
## 7 LF pH pH_je_up pH_je_down 24 24 1.24 2.14e- 1 2.14e- 1
## 8 LF pH pH_je_up pH_ileum 24 24 5.09 3.54e- 7 1.42e- 6
## 9 LF pH pH_je_up pH_cecum 24 23 7.50 6.62e-14 3.97e-13
## 10 LF pH pH_je_down pH_ileum 24 24 3.85 1.19e- 4 3.57e- 4
## 11 LF pH pH_je_down pH_cecum 24 23 6.27 3.73e-10 1.86e- 9
## 12 LF pH pH_ileum pH_cecum 24 23 2.46 1.40e- 2 2.80e- 2
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Calculate positions statistics on plot
pwc1 <- pwc1 %>% add_xy_position(x = "group", dodge = 0.8)
pwc2 <- pwc2 %>% add_xy_position(x = "group")
# Create plot
p <- ggboxplot(dat.clean, x = "group", y = "pH",
fill = "feedtreatday",
color = "feedtreatday",
add = "jitter",
add.params = list(size = 0.8)) +
theme_pubr(legend = "top") +
scale_color_manual(values = c("black","black","black","black","black","black","black","black")) +
scale_alpha_manual(values = c(1,0.5,1,0.5)) +
scale_y_continuous(name = "pH", breaks = seq(6,12,1)) +
scale_x_discrete(name = "Compartment", labels = c("pH_je_up" = "Jejunum\nUpper","pH_je_down" = "Jejunum\nLower","pH_ileum" = "Ileum","pH_cecum" = "Cecum")) +
theme(axis.title.x = element_blank()) +
guides(color = "none") +
facet_wrap("feed ~.", ncol = 2, nrow = 1)
p.stat <- p + stat_pvalue_manual(pwc1, tip.length = 0, hide.ns = TRUE, color = "red") +
stat_pvalue_manual(pwc2, tip.length = 0, hide.ns = TRUE)
p.statsuppressMessages(ggsave(filename = "plots/animal_data/pH/pH_all_pfos.pdf", plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 200))
suppressMessages(ggsave(filename = "plots/animal_data/pH/pH_all_pfos.png", plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 200))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())9.6 Conclusion
Measurements of pH in diluted GI content show significant variations between compartments in the GI with a generally increasing pH the further “down” the sample is taken. The largest feed-driven difference is observed in the caecal content, where pH is markedly lower in the HF group.
10 TRANSIT TIME DATA
10.1 Prepare data
# load data
load("R_objects/animal_data.Rdata")
params <- readRDS("R_objects/animal_params.RDS")
#Isolate transit time data
dat.clean <- dat %>% select(rat_name, treatment, feed, feedtreat, dissection, cage, transit_0, transit_7, transit_20) %>% pivot_longer(., cols = c(transit_0, transit_7, transit_20), names_to = "transit", values_to = "min")
dat.clean <- dat.clean %>%
mutate("day" = case_when(transit == "transit_0" ~ "d0",
transit == "transit_7" ~ "d07",
transit == "transit_20" ~ "d20"))
dat.clean <- subset(dat.clean, !is.na(min))
# Set names of variables
PREDICTOR <- c("day","feedtreat")#"day"
OUTCOME <- "min"
SUBJECT <- "rat_name"
# Create formula
PREDICTOR.F <- ifelse(length(PREDICTOR) > 1, paste(PREDICTOR, collapse = "*"), PREDICTOR)
FORMULA <- as.formula(paste(OUTCOME,PREDICTOR.F, sep = " ~ "))
# Summary samples in groups
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "mean_sd")## # A tibble: 12 × 6
## feedtreat day variable n mean sd
## <chr> <chr> <fct> <dbl> <dbl> <dbl>
## 1 HF_CTRL d0 min 6 512. 163.
## 2 HF_PFOS d0 min 5 504 109.
## 3 LF_CTRL d0 min 6 562. 134.
## 4 LF_PFOS d0 min 6 589. 121.
## 5 HF_CTRL d07 min 12 774. 164.
## 6 HF_PFOS d07 min 12 702. 145.
## 7 LF_CTRL d07 min 12 851. 113.
## 8 LF_PFOS d07 min 12 846. 118.
## 9 HF_CTRL d20 min 6 853. 93.5
## 10 HF_PFOS d20 min 6 910 89.1
## 11 LF_CTRL d20 min 6 914 91.3
## 12 LF_PFOS d20 min 6 881. 122.
dat.clean %>% group_by(across(all_of(PREDICTOR))) %>% get_summary_stats(!!sym(OUTCOME), type = "full")## # A tibble: 12 × 15
## feedtreat day variable n min max median q1 q3 iqr mad
## <chr> <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 HF_CTRL d0 min 6 377 748 428. 404. 627 224. 58.6
## 2 HF_PFOS d0 min 5 354 626 539 434 567 133 129.
## 3 LF_CTRL d0 min 6 400 721 596. 445 649 204 136.
## 4 LF_PFOS d0 min 6 426 758 571 523 667 144 120.
## 5 HF_CTRL d07 min 12 444 970 804. 762. 859 96.8 95.6
## 6 HF_PFOS d07 min 12 456 876 702. 641 844. 202. 211.
## 7 LF_CTRL d07 min 12 669 993 847 802. 930 128. 128.
## 8 LF_PFOS d07 min 12 637 983 835 780 958. 178. 153.
## 9 HF_CTRL d20 min 6 750 1011 860. 788 871 83 79.3
## 10 HF_PFOS d20 min 6 775 1008 898 875. 985 110. 98.6
## 11 LF_CTRL d20 min 6 806 1029 893 854. 990 136. 100.
## 12 LF_PFOS d20 min 6 675 1018 889 844. 960. 116 110.
## # ℹ 4 more variables: mean <dbl>, sd <dbl>, se <dbl>, ci <dbl>
# Test for outliers
dat.clean %>%
group_by(across(all_of(PREDICTOR))) %>%
identify_outliers(!!sym(OUTCOME))## # A tibble: 3 × 11
## feedtreat day rat_name treatment feed dissection cage transit min
## <chr> <chr> <chr> <chr> <chr> <chr> <int> <chr> <int>
## 1 HF_CTRL d07 R25 CTRL HF d08 13 transit_7 479
## 2 HF_CTRL d07 R30 CTRL HF d08 15 transit_7 444
## 3 HF_CTRL d20 R35 CTRL HF d21 18 transit_20 1011
## # ℹ 2 more variables: is.outlier <lgl>, is.extreme <lgl>
# Check normality
# Build the linear model
model <- lm(FORMULA, data = dat.clean)
# Create a QQ plot of residuals
ggqqplot(residuals(model))## # A tibble: 1 × 3
## variable statistic p.value
## <chr> <dbl> <dbl>
## 1 residuals(model) 0.980 0.144
## # A tibble: 1 × 4
## df1 df2 statistic p
## <int> <int> <dbl> <dbl>
## 1 11 83 0.310 0.982
Data is normally distributed, has equal variance and three outliers, where one is critical. Therefore we can test the data with a one-way ANOVA test with Tukey’s honest significance test.
10.2 ANOVA One-Way test
Perform test
If we had equality of variance we can now run a one-way ANOVA tests
anova_test() (if we have equal variance) or a
welch_anova_test() (if variance vary).
if(EQUAL.VAR) {
res.aov <- dat.clean %>% anova_test(FORMULA)
res.aov
} else {
res.aov <- dat.clean %>% welch_anova_test(FORMULA)
res.aov
}## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges
## 1 day 2 83 47.397 1.86e-14 * 0.533
## 2 feedtreat 3 83 2.955 3.70e-02 * 0.097
## 3 day:feedtreat 6 83 0.774 5.93e-01 0.053
Perform posthoc test
if(EQUAL.VAR) {
pwc <- dat.clean %>% tukey_hsd(FORMULA)
pwc
} else {
pwc <- dat.clean %>% games_howell_test(FORMULA)
pwc
}## # A tibble: 75 × 9
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 day d0 d07 0 250. 173. 328. 1.87e-10
## 2 day d0 d20 0 346. 257. 435. 1.10e-10
## 3 day d07 d20 0 96.1 19.7 173. 9.84e- 3
## 4 feedtreat HF_CTRL HF_PF… 0 -24.3 -122. 73.7 9.15e- 1
## 5 feedtreat HF_CTRL LF_CT… 0 66.4 -30.5 163. 2.83e- 1
## 6 feedtreat HF_CTRL LF_PF… 0 62.4 -34.6 159. 3.37e- 1
## 7 feedtreat HF_PFOS LF_CT… 0 90.7 -7.26 189. 7.97e- 2
## 8 feedtreat HF_PFOS LF_PF… 0 86.7 -11.3 185. 1.02e- 1
## 9 feedtreat LF_CTRL LF_PF… 0 -4.04 -101. 92.9 1 e+ 0
## 10 day:feedtreat d0:HF_C… d07:H… 0 263. 47.3 478. 5.1 e- 3
## # ℹ 65 more rows
## # ℹ 1 more variable: p.adj.signif <chr>
Significant impact is observed on both day and grouping (feedtreat). Based on the data we see a difference between all days. We will plot this as a nested analysis using ANOVA with Tukey’s HSD on both the inner variable and the outer variable.
10.3 Create figure (feedtreat)
## Comparison for inner variable
stat.in <- dat.clean %>%
group_by(day) %>%
anova_test(min ~ feedtreat) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 3 × 10
## day Effect DFn DFd F p `p<.05` ges p.signif p.format
## * <chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <dbl> <chr> <chr>
## 1 d0 feedtreat 3 19 0.523 0.671 "" 0.076 ns 0.671
## 2 d07 feedtreat 3 44 3.20 0.032 "*" 0.179 * 0.032
## 3 d20 feedtreat 3 20 0.486 0.696 "" 0.068 ns 0.696
pwc1 <- dat.clean %>%
group_by(day) %>%
tukey_hsd(min ~ feedtreat) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc1## # A tibble: 18 × 11
## day term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 d0 feedtreat HF_CTRL HF_PFOS 0 -7.5 -236. 221. 1
## 2 d0 feedtreat HF_CTRL LF_CTRL 0 51.0 -167. 269. 0.912
## 3 d0 feedtreat HF_CTRL LF_PFOS 0 77.2 -141. 295. 0.754
## 4 d0 feedtreat HF_PFOS LF_CTRL 0 58.5 -170. 287. 0.888
## 5 d0 feedtreat HF_PFOS LF_PFOS 0 84.7 -144. 313. 0.728
## 6 d0 feedtreat LF_CTRL LF_PFOS 0 26.2 -192. 244. 0.986
## 7 d07 feedtreat HF_CTRL HF_PFOS 0 -72.3 -221. 76.5 0.569
## 8 d07 feedtreat HF_CTRL LF_CTRL 0 76.9 -71.9 226. 0.518
## 9 d07 feedtreat HF_CTRL LF_PFOS 0 72.3 -76.5 221. 0.569
## 10 d07 feedtreat HF_PFOS LF_CTRL 0 149. 0.452 298. 0.0491
## 11 d07 feedtreat HF_PFOS LF_PFOS 0 145. -4.13 293. 0.0594
## 12 d07 feedtreat LF_CTRL LF_PFOS 0 -4.58 -153. 144. 1
## 13 d20 feedtreat HF_CTRL HF_PFOS 0 56.8 -104. 218. 0.758
## 14 d20 feedtreat HF_CTRL LF_CTRL 0 60.8 -100. 222. 0.719
## 15 d20 feedtreat HF_CTRL LF_PFOS 0 27.7 -133. 189. 0.963
## 16 d20 feedtreat HF_PFOS LF_CTRL 0 4.00 -157. 165. 1
## 17 d20 feedtreat HF_PFOS LF_PFOS 0 -29.2 -190. 132. 0.957
## 18 d20 feedtreat LF_CTRL LF_PFOS 0 -33.2 -194. 128. 0.938
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Comparison for outer variable
stat.out <- dat.clean %>%
anova_test(min ~ day) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges p.signif p.format
## 1 day 2 92 44.597 2.88e-14 * 0.492 **** <0.001
pwc2 <- dat.clean %>%
tukey_hsd(min ~ day) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 3 × 10
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 day d0 d07 0 250. 171. 329. 5.90e-10
## 2 day d0 d20 0 346. 255. 437. 4.82e-10
## 3 day d07 d20 0 96.1 18.0 174. 1.18e- 2
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Calculate positions statistics on plot
pwc1 <- pwc1 %>% add_xy_position(x = "day", dodge = 0.8)
pwc2 <- pwc2 %>% add_xy_position(x = "day")
pwc2$y.position <- max(pwc1$y.position)*1.1
# Create list of mean and sd for plotting
dat.sum2 <- dat.clean %>% group_by(across(all_of(c("feedtreat","day")))) %>% get_summary_stats(!!sym("min"), type = "mean_sd")
# Plot
p <- ggplot() +
geom_crossbar(data=dat.sum2,
aes(x = day, y = mean, ymin = mean, ymax = mean, color = feedtreat),
linewidth=0.1, width = .7,
position = position_dodge(width = 0.8)) +
geom_errorbar(data=dat.sum2,
aes(x = day,y = mean, ymin = mean-sd, ymax = mean+sd, color = feedtreat),
linewidth=0.1, width = .3,
position = position_dodge(width = 0.8)) +
geom_jitter(data = dat.clean, aes(x = day, y = min, color = feedtreat), position = position_jitterdodge(jitter.width = 0.1, dodge.width = 0.8)) +
scale_x_discrete(name = "Day", labels = c("Day 0","Day 7","Day 21")) +
scale_y_continuous(name = "Transit time per rat (Minutes)", breaks = seq(360,1120,60)) +
scale_color_manual(values = params$COL1, name = "Group", labels = c("HF-CTRL","HF-PFOS","LF-CTRL","LF-PFOS")) +
theme_pubr() +
theme(axis.title.x = element_blank())
pp.stat <- p + stat_pvalue_manual(pwc1, tip.length = 0, hide.ns = TRUE, y.position = 1030, color = "red") +
stat_pvalue_manual(pwc2, tip.length = 0, hide.ns = TRUE,y.position = c(1110,1140,1080))
p.stat# Save output
suppressMessages(ggsave(filename = "plots/animal_data/transit/transit_time_feedtreat.pdf", plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 130))
suppressMessages(ggsave(filename = "plots/animal_data/transit/transit_time_feedtreat.png", plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 130))10.4 Create figure (feed)
## Comparison for inner variable
stat.in <- dat.clean %>%
group_by(day) %>%
t_test(min ~ feed,
paired = FALSE, var.equal = EQUAL.VAR,
detailed = TRUE, alternative = "two.sided") %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.in## # A tibble: 3 × 18
## day estimate estimate1 estimate2 .y. group1 group2 n1 n2 statistic
## * <chr> <dbl> <dbl> <dbl> <chr> <chr> <chr> <int> <int> <dbl>
## 1 d0 -67.5 508. 576. min HF LF 11 12 -1.26
## 2 d07 -111. 738 849. min HF LF 24 24 -2.82
## 3 d20 -15.8 882. 897. min HF LF 12 12 -0.395
## # ℹ 8 more variables: p <dbl>, df <dbl>, conf.low <dbl>, conf.high <dbl>,
## # method <chr>, alternative <chr>, p.signif <chr>, p.format <chr>
## Comparison for outer variable
stat.out <- dat.clean %>%
anova_test(min ~ day) %>%
add_significance() %>%
p_format("p", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
stat.out## ANOVA Table (type II tests)
##
## Effect DFn DFd F p p<.05 ges p.signif p.format
## 1 day 2 92 44.597 2.88e-14 * 0.492 **** <0.001
pwc2 <- dat.clean %>%
tukey_hsd(min ~ day) %>%
add_significance() %>%
p_format("p.adj", accuracy = 0.001, trailing.zero = TRUE, new.col = TRUE)
pwc2## # A tibble: 3 × 10
## term group1 group2 null.value estimate conf.low conf.high p.adj
## * <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 day d0 d07 0 250. 171. 329. 5.90e-10
## 2 day d0 d20 0 346. 255. 437. 4.82e-10
## 3 day d07 d20 0 96.1 18.0 174. 1.18e- 2
## # ℹ 2 more variables: p.adj.signif <chr>, p.adj.format <chr>
## Calculate positions statistics on plot
stat.in <- stat.in %>% add_xy_position(x = "day", dodge = 0.8)
pwc2 <- pwc2 %>% add_xy_position(x = "day")
pwc2$y.position <- max(stat.in$y.position)*1.1
# Create list of mean and sd for plotting
dat.sum2 <- dat.clean %>% group_by(across(all_of(c("feed","day")))) %>% get_summary_stats(!!sym("min"), type = "mean_sd")
# Plot
p <- ggplot() +
geom_crossbar(data=dat.sum2,
aes(x = day, y = mean, ymin = mean, ymax = mean, color = feed),
linewidth=0.1, width = .7,
position = position_dodge(width = 0.8)) +
geom_errorbar(data=dat.sum2,
aes(x = day,y = mean, ymin = mean-sd, ymax = mean+sd, color = feed),
linewidth=0.1, width = .3,
position = position_dodge(width = 0.8)) +
geom_jitter(data = dat.clean, aes(x = day, y = min, color = feed), position = position_jitterdodge(jitter.width = 0.1, dodge.width = 0.8)) +
scale_x_discrete(name = "Day", labels = c("Day 0","Day 7","Day 21")) +
scale_y_continuous(name = "Transit time per rat (Minutes)", breaks = seq(360,1120,60)) +
scale_color_manual(values = params$COLFEED, name = "Feed", labels = c("HF","LF")) +
theme_pubr() +
theme(axis.title.x = element_blank()) +
guides(color = guide_legend(override.aes = list(size = 4, shape = 15, linetype = 0)))
pp.stat <- p + stat_pvalue_manual(stat.in, tip.length = 0, hide.ns = TRUE, y.position = 1030, color = "red") +
stat_pvalue_manual(pwc2, tip.length = 0, hide.ns = TRUE,y.position = c(1110,1140,1080))
p.stat# Save output
suppressMessages(ggsave(filename = "plots/animal_data/transit/transit_time_feed.pdf", plot = p.stat, device = "pdf", dpi = 300, units = "mm", height = 100, width = 130))
suppressMessages(ggsave(filename = "plots/animal_data/transit/transit_time_feed.png", plot = p.stat, device = "png", dpi = 300, units = "mm", height = 100, width = 130))
# clear the environment and release memory
rm(list = ls(all.names = TRUE)[ls(all.names = TRUE) != "params"])
invisible(gc())10.5 Conclusion
Transit time was significantly shorter in HF at Day 7 but not at other times. It should be noted that shorts measurement are generally in HF rats.
11 SETTINGS
Overview of the parameters and packages that were used for this analysis
11.1 PARAMETERS
The following paramenters were set in for this analysis:
11.2 PACKAGES
The analysis was run in R version 4.3.1 using the following packages:
pack <- data.frame(Package = (.packages()))
for (i in seq(nrow(pack))) pack$Version[i] <- as.character(packageVersion(pack$Package[i]))
kbl(pack[order(pack$Package),], row.names = F) %>% kable_classic(lightable_options = "striped") | Package | Version |
|---|---|
| ape | 5.7.1 |
| base | 4.3.1 |
| cowplot | 1.1.1 |
| datasets | 4.3.1 |
| DAtest | 2.8.0 |
| decontam | 1.20.0 |
| dplyr | 1.1.4 |
| forcats | 1.0.0 |
| ggplot2 | 3.4.4 |
| ggpubr | 0.6.0 |
| ggrepel | 0.9.4 |
| graphics | 4.3.1 |
| grDevices | 4.3.1 |
| kableExtra | 1.3.4 |
| lattice | 0.22.5 |
| lubridate | 1.9.3 |
| methods | 4.3.1 |
| pals | 1.8 |
| permute | 0.9.7 |
| phangorn | 2.11.1 |
| phyloseq | 1.44.0 |
| plotly | 4.10.3 |
| purrr | 1.0.2 |
| readr | 2.1.4 |
| rstatix | 0.7.2 |
| stats | 4.3.1 |
| stringr | 1.5.1 |
| tibble | 3.2.1 |
| tidyr | 1.3.0 |
| tidyverse | 2.0.0 |
| utils | 4.3.1 |
| vegan | 2.6.4 |